This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

Import necessary libraries

library(tidyverse)

Importing necesary CSV files

#Setting working directory
setwd("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets/transcriptomic_datasheets")
Warning: The working directory was changed to /Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets/transcriptomic_datasheets inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
#Importing trancriptomic datasdets
Talkowski2014 <- read.csv("Talkowski_2014_TableS3_Human_Del.csv")
Urresti2021_3M_organoid <- read.csv("Urresti-2021_DEG-3M-cortical-organoid.csv")
Roth2020 <-  read.csv("Roth_2020_DEG-hIPSC-neural-endodermMesoderm.csv")
#Importing file containing 16p11.2 gene list
chr16p11.2_gene_list_Kusenda2015 <-  read.csv("Kusenda_2015_TableS1_16p11.2_gene_list.csv")
#Creating a vector of all genes in the 16p11.2 chromosomal region
sixteenP11.2_genes <- chr16p11.2_gene_list_Kusenda2015$Gene.symbol

Modifying dataframes, such that they have the same column names, in order to combine them

  1. Uresti 2021 cortical organoids data
Urresti2021_3M_organoid_tidy <- Urresti2021_3M_organoid %>%
  #remove columns that i do not need
  select(-c("Gene.Biotype", "log2.FC..DUP.vs.DEL", "P.value..DUP.vs.DEL", "FDR.adjusted.P.value..DUP.vs.DEL", "log2.FC..DUP.vs.CTL",
            "P.value..DUP.vs.CTL", "FDR.adjusted.P.value..DUP.vs.CTL", "FDR.adjusted.P.value..DEL.vs.CTL")) %>%
  #rename columns to the standardized names I decided on
  rename("gene_name" = "HGNC.Symbol",
         "log2_fold_change" = "log2.FC..DEL.vs.CTL",
         "p_value" = "P.value..DEL.vs.CTL",
         "gene_description" = "Description", 
         "ENSEMBL_ID" = "ENSEMBL.ID") %>%
  #add a column for the data source
  mutate( "sample_type" = "cortical organoid", "data_source" = "Urresti et al. 2021", "Present.in.the.16p11.2.Region" = "") %>%
  #reorder columns so that the ensemble_ID column, which not all dataframes will have, is at the end
  relocate("ENSEMBL_ID", .after = "data_source")
  1. Roth 2020 data
Roth2020_tidy <- Roth2020 %>%
  # remove columns that I do not need
  select(-c("SFARI.Gene.Score", "SFARI.Gene.Score.Category", "https...gene.sfari.org.about.gene.scoring.criteria.")) %>%
  #rename columns to the standardized names I decided on
  rename("gene_name" = "X16p11.2.DE.Genes",
         "log2_fold_change" = "Log2.Fold.Change..Positive.values.are.upregulated.in.DEL.",
         "p_value" = "Adjusted.P.Value") %>%
  #add columns for the data source, sample type, and extras to match the above dataset
  mutate("gene_description" = "", "sample_type" = "hIPSC", "data_source" = "Roth et al. 2020", "ENSEMBL_ID" = "") %>%
  #reorder columns to match the other dataframes
  relocate("gene_description", .after = "gene_name") %>%
  relocate("Present.in.the.16p11.2.Region", .after = "ENSEMBL_ID")
  1. Talkowski 2014 data
Talkowski2014_tidy <- Talkowski2014 %>% 
  select(-c("GeneInfo", "Chr", "Start", "Stop")) %>%
  #select(-c("GeneInfo", "Chr", "Start", "Stop")) %>%
  #Transforming the foldchange to log2 foldchange
  mutate("FoldChange" = log2(FoldChange)) %>%
  #rename columns to the standardized names I decided on
  rename("gene_name" = "GeneID",
         "log2_fold_change" = "FoldChange",
         "p_value" = "permPval_Del") %>%
  #add columns for the data source, sample type, and extras to match the above dataset
  mutate("gene_description" = "", "sample_type" = "hLCL", "data_source" = "Talkowski et al. 2014", "ENSEMBL_ID" = "", "Present.in.the.16p11.2.Region" = "") %>%
  #reorder columns to match the other dataframes
  relocate("gene_description", .after = "gene_name") %>%
  relocate("p_value", .after = "log2_fold_change")

Potential next step: I tried to add in the ensembl ID for the Talkowski 2014 data, but that dataset used an old refrence transcriptome and so, using the chromosomal start and stop positions and chromosome number, I was unable to find the ensembl ID for the genes in that dataset. I

Now, I want to fill in the “Present.in.the.16p11.2.Region” column for the DEG_all_timepoints_organoid_Urresti2021_modified_columns dataframe.

# The vector sixteenP11.2_genes is a vector containing all genes located in the 16p11.2 chromosomal region
# I want to change the value of the "Present.in.the.16p11.2.Region" column to "Yes" if the gene name is in the vector, and "No" if it is not

Urresti2021_3M_organoid_tidy$Present.in.the.16p11.2.Region <-
  ifelse(Urresti2021_3M_organoid_tidy$gene_name %in% sixteenP11.2_genes, "Yes", "No")
Roth2020_tidy$Present.in.the.16p11.2.Region <-
  ifelse(Roth2020_tidy$gene_name %in% sixteenP11.2_genes, "Yes", "No")
Talkowski2014_tidy$Present.in.the.16p11.2.Region <-
  ifelse(Talkowski2014_tidy$gene_name %in% sixteenP11.2_genes, "Yes", "No")

Now I combine all 3 organized dataframes into 1 dataframe

all_DEG_data <- rbind(Urresti2021_3M_organoid_tidy, Roth2020_tidy, Talkowski2014_tidy)

# Now, I want to look at the genes in the 16p11.2 region only, from the all DEG data. So I will filter the all_DEG_data dataframe to only include those genes
all_DEG_16p_genes <- all_DEG_data %>%
  filter(Present.in.the.16p11.2.Region == "Yes")

No I will do a metaanalysis to combine every instance of a gene into one row, so that I can see all the data for each gene in one row Log fold change is weighted by p-value p values are combined with fishers exact test

meta_analysis_all_DEG_data <- all_DEG_data %>%
  group_by(gene_name) %>%
  summarize(combined_log2_fold_change = sum(log2_fold_change / (p_value + 1e-8)) / sum(1 / (p_value + 1e-8)),  # Weighted logFC using p-values.
            # A small constant (1e-8) is added to avoid division by zero if there are very small p-values.
            #in the next line of code I will do a fisher test to combine the p-values
            combined_p_value = 1 - pchisq(sum(qchisq(1 - p_value, 1, lower.tail = FALSE)), length(p_value), lower.tail = FALSE)) %>%
  #the above code will return a dataframe that only contains 3 of the columns. In the next line of code I will bring the rest of the columns back to this new dataframe
  left_join(all_DEG_data, by = "gene_name")


#Keep track of if the gene combined logfoldcahnge and p-value are from multiple data sources
meta_analysis_all_DEG_data$multiple_data_sources <- ifelse(duplicated(meta_analysis_all_DEG_data$gene_name) | duplicated(meta_analysis_all_DEG_data$gene_name, fromLast = TRUE), "Yes", "No")


#Now, I want to delete rows that have the same gene name and remove the columns that have the original log2_fold_change, p_value, sample_type, and data_source
meta_analysis_all_DEG_data <- meta_analysis_all_DEG_data %>%
  distinct(gene_name, .keep_all = TRUE) %>%
  select(-c(log2_fold_change, p_value, sample_type, data_source))

#This code adds a column called significance that will indicate the degree of significance, just like Smrithi's code
meta_analysis_all_DEG_data <- meta_analysis_all_DEG_data %>%
  mutate("significance" = case_when(
    combined_p_value < 0.001 ~ "***",
    combined_p_value < 0.01 ~ "**",
    combined_p_value < 0.05 ~ "*",
    TRUE ~ " "
  ))

#Now i will create a new dataframe with only the genes that are significantly differentially expressed at combined p-value < 0.001
sig_genes_p0.001_DEG_data <- meta_analysis_all_DEG_data %>%
  filter(significance == "***")

Exporting the dataframes to CSV files, if desired

setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")

write.csv(Urresti2021_3M_organoid_tidy, file="Urresti2021_3M_organoid_tidy.csv")
write.csv(Roth2020_tidy, file="Roth2020_tidy.csv")
write.csv(Talkowski2014_tidy, file="Talkowski2014_tidy.csv")
write.csv(all_DEG_data, file="all_DEG_data.csv")
write.csv(meta_analysis_all_DEG_data, file="meta_analysis_all_DEG_data.csv")
write.csv(sig_genes_p0.001_DEG_data, file="sig_genes_p0.001_DEG_data.csv")

Gene ontology analysis I am using gprofiler2 to do my GO analysis Loading gprofiler2 package

library(gprofiler2)

Doing GO analysis

# Making vector of genes in sig gene dataframe
exp_gene_list_1_p_0.001 <- sig_genes_p0.001_DEG_data$gene_name

# using gost function frmo gprofiler2 to do GO analysis
GO_results_exp_gene_list_p0.001 = gost(query = exp_gene_list_1_p_0.001,
               organism = "hsapiens",
               correction_method = "fdr")
GO_all_results_p0.001 <- GO_results_exp_gene_list_p0.001$result %>%
  select(-parents)

#putting metadata from GO analysis into a dataframe
GO_meta_p0.001 <- GO_results_exp_gene_list_p0.001$meta


#Creating gene lists for upregulated and downregulated genes
UPregulated_sig_genes_p0.001_DEG_data <- sig_genes_p0.001_DEG_data %>%
  filter(combined_log2_fold_change > 0)
UPregulated_exp_gene_list_1_p_0.001 <- UPregulated_sig_genes_p0.001_DEG_data$gene_name

DOWNregulated_sig_genes_p0.001_DEG_data <- sig_genes_p0.001_DEG_data %>%
  filter(combined_log2_fold_change < 0)
DOWNregulated_sig_genes_p0.001_DEG_data <- DOWNregulated_sig_genes_p0.001_DEG_data$gene_name

up_reg_genes <- sig_genes_p0.001_DEG_data %>% filter(combined_log2_fold_change > 0)
up_reg_gene_names <- up_reg_genes$gene_name

# GO analysis of upregulated and downregulated genes
gostres_UPregulated <- gost(query = UPregulated_exp_gene_list_1_p_0.001,
               organism = "hsapiens",
               correction_method = "fdr")

gostres_UPregulated <- gostres_UPregulated$result


gostres_DOWNregulated <- gost(query = DOWNregulated_sig_genes_p0.001_DEG_data,
                            organism = "hsapiens",
                            correction_method = "fdr")

gostres_DOWNregulated <- gostres_DOWNregulated$result

Exporting the GO analysis dataframes to CSV files, if desired

setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")
write.csv(gostres_results, file="/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/output/GO_16p11.2-DEGs_p0.001_fdr-corrections.csv", row.names = FALSE)

NOW, we generate map of our significant genes to AHBA spatial map

First, read in the data

AHBA <- read_tsv("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets/AllenHBA_DK_ExpressionMatrix.tsv")
New names:
• `` -> `...1`
Rows: 20736 Columns: 70
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: "\t"
chr  (1): ...1
dbl (69): Average donor correlation to median, ctx-rh-insula, ctx-lh-paracentral, ctx-rh-precuneus, ctx-lh-medialorbitofrontal, ctx-rh-inferiortemporal, ctx-rh-medialorbitofrontal...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Now, I want to cchange the column header of the first column of the AHBA dataframe to gene_symbol
colnames(AHBA)[1] <- "gene_symbol"

Mapping our significant genes to the AHBA dataset

#Creating vector of gene names in our experimental groups
sig_genes_p0.001_DEG_data #dataframe containing all significant genes
sig_gene_list <- sig_genes_p0.001_DEG_data$gene_name #vector of all significant genes names
sixteenP11.2_genes #dataframe containing all genes in 16p11.2 locus
 [1] "SLC7A5P1"  "SPN"       "QPRT"      "C16orf54"  "ZG16"      "KIF22"     "MAZ"       "PRRT2"     "C16orf53"  "MVP"       "CDIPT"     "LOC440356" "SEZ6L2"    "ASPHD1"   
[15] "KCTD13"    "TMEM219"   "TAOK2"     "HIRIP3"    "INO80E"    "DOC2A"     "C16orf92"  "FAM57B"    "ALDOA"     "PPP4C"     "TBX6"      "YPEL3"     "GDPD3"     "MAPK3"    
[29] "CORO1A"    "BOLA2"     "SLX1A"     "SULT1A3"   "IMMA"      "SMG1 "    
sixteen_p_11.2_genes <- chr16p11.2_gene_list_Kusenda2015$Gene.symbol #vector of all genes in 16p locus

AHBA_sig_genes <- AHBA %>% filter(gene_symbol %in% sig_gene_list)

#NOTE: not all sig genes mapped to AHBA dataset. Here is a list of them so I can troubleshoot later
genes_not_mapped <- sig_gene_list[!(sig_gene_list %in% AHBA_sig_genes$gene_symbol)]

NOTE: Only 87 of the 132 genes mapped to the AHBA dataset

Tidying the AHBA subset dataframe with significant genes only

AHBA_sig_genes_pivot <- AHBA_sig_genes %>%
  #remove the "Average donor correlation to the median" column
  select(-"Average donor correlation to median") %>%
  pivot_longer(cols = -gene_symbol, names_to = "region", values_to = "expression") %>%
  #adding a column for if gene is in the 16p region
  mutate(in_16p_region = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No")) %>%
  # Adding a column for if gene is up or downregulated
  mutate(upreg = ifelse(gene_symbol %in% up_reg_gene_names, "Yes", "No"))

GGplot to visualize the data

# Visualizing expression data of significant genes
ggplot(AHBA_sig_genes_pivot, aes(x=expression, y=region, shape=in_16p_region, color=gene_symbol)) + 
  geom_point() + 
  labs(title = "regional expression of significant genes from 16p del meta-analysis", x = "Raw Expression", y = "Brain Region") +
  theme_minimal() +
  #I will make the legend smaller and put it underneath the graph  because it is too big
  theme(legend.position = "bottom") +
  guides(color="none")


# same plot but aesthetics only for genes in 16p region
ggplot(AHBA_sig_genes_pivot, aes(x=expression, y=region, color=in_16p_region)) + 
  geom_point() + 
  labs(title = "regional expression of significant genes from 16p del meta-analysis", x = "Raw Expression", y = "Brain Region") +
  theme_minimal() +
  #I will make the legend smaller and put it underneath the graph  because it is too big
  theme(legend.position = "bottom") 



ggplot(AHBA_sig_genes_pivot, aes(x=expression, y=region, color=upreg)) + 
  geom_point() + 
  labs(title = "regional expression of significant genes from 16p del meta-analysis", x = "Raw Expression", y = "Brain Region") +
  theme_minimal() +
  #I will make the legend smaller and put it underneath the graph  because it is too big
  theme(legend.position = "bottom") 

Now, we want to work with the normalized AHBA values. They are in a matlab file, so first I will need to convert the matlab file to something R can read, with the R.matlab package. NOTE: The R.matlab package does not keep column names of the original data when converting things, so I had to add them back in.

First, load libraries

library(R.matlab)

Second, load in relevant files

setwd("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics")
Warning: The working directory was changed to /Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
AHBA_normed <- readMat("ROIxGene_aparcaseg_INT.mat")

setwd("/Users/tammyray/Desktop/Aaron_16p_Imaging_Transcriptomics/CSV_data_sheets")
region_array <- read_csv("Region_labels_for_aparcaseg_parcellation.csv", col_names = FALSE)
Rows: 34 Columns: 1
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): X1

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Tidying up the AHBA_normed dataframe

AHBA_parcel_expression0 <- as.data.frame(AHBA_normed$parcelExpression)
# Getting list of gene names 
array_gene_names <- unlist(AHBA_normed$probeInformation[[2]])
# First i need to edit my array_gene_names to add a 0 as the first item in my array
array_gene_names <- c(0, array_gene_names)
# Now, I want to rename the columns of the AHBA_parcel_expression dataframe to the gene names in array_gene_names
colnames(AHBA_parcel_expression0) <- array_gene_names

#Now, I want to change the values of column 1 of the AHBA_parcel_expression0 dataframe to the values in the region_array dataframe
#Maybe I just mutate the dataframe to add the array as a column, move that column to the front, and then remove the original column
AHBA_parcel_expression0_labeled <- AHBA_parcel_expression0 %>%
  mutate(region = region_array) %>%
  #Now i want to move the region$x1 var to be the first column
  select(region, everything()) %>%
  select(-"0")

#Yay now data table is as i want it to be!
# Now I will pivot the table so that it matches the AHBA_sig_genes_all_pivot table
AHBA_normed_pivot <- AHBA_parcel_expression0_labeled %>%
  pivot_longer(cols = -region, names_to = "gene_symbol", values_to = "expression") %>%
  mutate(in_16p_region = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No")) %>%
  unnest(cols = region)



AHBA_normed_pivot_sigONLY <- AHBA_normed_pivot %>%
  filter(gene_symbol %in% sig_gene_list)


# Now, I want to change the column name X1 to region
colnames(AHBA_normed_pivot_sigONLY)[1] <- "region"

Exporting dataframes as CSVs

# OK, Now that I have this data, I want to put it into a CSV so I have it for future reference
setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")
Warning: The working directory was changed to /Users/tammyray/Desktop/aaron_lab_2024/output inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
write.csv(AHBA_normed_pivot, "Normed_AHBA_sig_genes.csv")
write.csv(AHBA_normed_pivot_sigONLY, "Normed_AHBA_sig_genes_ONLY.csv")
write.csv(AHBA_sig_genes_pivot, "Raw_AHBA_sig_genes_ONLY.csv")

Plotting the normalized AHBA data

ggplot(AHBA_normed_pivot_sigONLY, aes(x=expression, y=region, color=gene_symbol)) + 
  geom_point() + 
  labs(title = "NORMALIZED regional expression of significant genes from 16p del meta-analysis", x = "Normalized Expression", y = "Brain Region") +
  theme_minimal() +
  #I will remove the legend because it is too big
  theme(legend.position = "none")



# Visualizing expression data of significant genes
ggplot(AHBA_normed_pivot_sigONLY, aes(x=expression, y=region, shape=in_16p_region, color=gene_symbol)) + 
  geom_point() + 
  labs(title = "NORMALIZED regional expression of significant genes from 16p del meta-analysis", x = "Normalized Expression", y = "Brain Region") +
  theme_minimal() +
  #I will make the legend smaller and put it underneath the graph  because it is too big
  theme(legend.position = "bottom") +
  guides(color="none")


# same plot but aesthetics only for genes in 16p region
ggplot(AHBA_normed_pivot_sigONLY, aes(x=expression, y=region, color=in_16p_region)) + 
  geom_point() + 
  labs(title = "NORMALIZED regional expression of significant genes from 16p del meta-analysis", x = "Normalized Expression", y = "Brain Region") +
  theme_minimal() +
  #I will make the legend smaller and put it underneath the graph  because it is too big
  theme(legend.position = "bottom") 

Now I will map the normalized AHBA data to Smrithi’s MRI data, which is in a csv file: 16panalysis_BH_adjusted.csv

Importing necessary files

# Importing Smrithi's MRI dataset
setwd("/Users/tammyray/Desktop/aaron_lab_2024/output")
Warning: The working directory was changed to /Users/tammyray/Desktop/aaron_lab_2024/output inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
MRI <- read_csv("16panalysis_BH_adjusted.csv")
Rows: 1224 Columns: 10
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): Genotype, Model, VolumetricComponent, Significance
dbl (6): Estimate, Std. Error, t value, Pr(>|t|), SigPos, adjusted_p

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Outside of R, I have made a CSV of corresponding AHBA and Smrithi MRI data region names. First column is AHBA names, second column is MRI names.
# Importing the data
setwd("/Users/tammyray/Desktop/aaron_lab_2024/CSV_data_sheets")
standard_region_names <- read_csv("AHBA_MRI_region_names.csv")
Rows: 34 Columns: 2
── Column specification ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): AHBA regions, left hemisphere Smrithi regions

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Remembering other files I will use in the following chunks
sixteen_p_11.2_genes #vector of all genes in 16p locus
 [1] "SLC7A5P1"  "SPN"       "QPRT"      "C16orf54"  "ZG16"      "KIF22"     "MAZ"       "PRRT2"     "C16orf53"  "MVP"       "CDIPT"     "LOC440356" "SEZ6L2"    "ASPHD1"   
[15] "KCTD13"    "TMEM219"   "TAOK2"     "HIRIP3"    "INO80E"    "DOC2A"     "C16orf92"  "FAM57B"    "ALDOA"     "PPP4C"     "TBX6"      "YPEL3"     "GDPD3"     "MAPK3"    
[29] "CORO1A"    "BOLA2"     "SLX1A"     "SULT1A3"   "IMMA"      "SMG1 "    

Tidying Smrithi’s MRI data

# We decided that we only want to use model 3, Spline TCV model (decided w Smrithi meeting 8/24/24)
# We are only using the deletion data for now
MRI_model3 <- MRI %>%
  filter(Genotype == "Genotype16pDeletion...5")

#MRI regions to remove. I made this list manually using google sheets and reformatted it for R using chatgpt
MRI_regions_to_remove <- c("L.Cerebral_WM", "L.cerebral_cortex", "L.lateral_ventricle", "L.inferior_lateral_ventricle", "L.cerebellum_WM", "L.cerebellum_cortex", 
                           "L.thalamus", "L.caudate", "L.putamen", "L.pallidum", "L.accumbens", "L.hippocampus", "L.amygdala", "L.ventral_DC", "Third_Ventricle", 
                           "Fourth_Ventricle", "Brainstem", "CSF", "R.Cerebral_WM", "R.cerebral_cortex", "R.lateral_ventricle", "R.inferior_lateral_ventricle", 
                           "R.cerebellum_WM", "R.cerebellum_cortex", "R.thalamus", "R.caudate", "R.putamen", "R.pallidum", "R.hippocampus", "R.amygdala", "R.accumbens", 
                           "R.ventral_DC", "R.ctx_bankssts", "R.ctx_caudalanteriorcingulate", "R.ctx_caudalmiddlefrontal", "R.ctx_cuneus", "R.ctx_entorhinal", "R.ctx_fusiform", 
                           "R.ctx_inferiorparietal", "R.ctx_inferiortemporal", "R.ctx_isthmuscingulate", "R.ctx_lateraloccipital", "R.ctx_lateralorbitofrontal", "R.ctx_lingual", 
                           "R.ctx_medialorbitofrontal", "R.ctx_middletemporal", "R.ctx_parahippocampal", "R.ctx_paracentral", "R.ctx_parsopercularis", "R.ctx_parsorbitalis", 
                           "R.ctx_parstriangularis", "R.ctx_pericalcarine", "R.ctx_postcentral", "R.ctx_posteriorcingulate", "R.ctx_precentral", "R.ctx_precuneus", 
                           "R.ctx_rostralanteriorcingulate", "R.ctx_rostralmiddlefrontal", "R.ctx_superiorfrontal", "R.ctx_superiorparietal", "R.ctx_superiortemporal", 
                           "R.ctx_supramarginal", "R.ctx_frontalpole", "R.ctx_temporalpole", "R.ctx_transversetemporal", "R.ctx_insula", "cGMV", "WMV", "sGMV", "Ventricles", 
                           "Cerebellum", "Accumbens", "Ventral_Diencephalon", "Pallidum", "Hippocampus", "Caudate", "Cerebral_White_Matter", "Lateral_Ventricle", "Cerebral_Cortex", 
                           "Thalamus", "Putamen", "Amygdala", "Cerebellar_White_Matter", "Cerebellar_Cortex", "Inferior_Lateral_Ventricle", "ctx_bankssts", "ctx_caudalanteriorcingulate", 
                           "ctx_caudalmiddlefrontal", "ctx_cuneus", "ctx_entorhinal", "ctx_fusiform", "ctx_inferiorparietal", "ctx_inferiortemporal", "ctx_isthmuscingulate", 
                           "ctx_lateraloccipital", "ctx_lateralorbitofrontal", "ctx_lingual", "ctx_medialorbitofrontal", "ctx_middletemporal", "ctx_parahippocampal", 
                           "ctx_paracentral", "ctx_parsopercularis", "ctx_parsorbitalis", "ctx_parstriangularis", "ctx_pericalcarine", "ctx_postcentral", "ctx_posteriorcingulate", 
                           "ctx_precentral", "ctx_precuneus", "ctx_rostralanteriorcingulate", "ctx_rostralmiddlefrontal", "ctx_superiorfrontal", "ctx_superiorparietal", 
                           "ctx_superiortemporal", "ctx_supramarginal", "ctx_frontalpole", "ctx_temporalpole", "ctx_transversetemporal", "ctx_insula")

# removing rows for the regions we aren't including
MRI_model3_leftHem <- MRI_model3 %>%
  filter(VolumetricComponent %in% MRI_regions_to_remove == FALSE) %>%
  rename(region = VolumetricComponent)

# Now, I want to use the standard region
standard_region_names <- standard_region_names %>%
  rename(region = "left hemisphere Smrithi regions",
         new_region = "AHBA regions")

# Use left_join to map the new names based on the region variable
MRI_model3_leftHem_new_regionNames <- MRI_model3_leftHem %>%
  left_join(standard_region_names, by = "region") %>%   # Join based on the region variable
  mutate(region = ifelse(!is.na(new_region), new_region, region)) %>%   # Replace region names with new ones
  select(-new_region)  # Remove the extra column if needed

Merging the AHBA normed values with Smrithi’s MRI data

AHBA_MRI_merged <- full_join(AHBA_normed_pivot_sigONLY, MRI_model3_leftHem_new_regionNames, by = "region", multiple = "all")

AHBA_MRI_merged_organized <- AHBA_MRI_merged %>%
  select(-Genotype)

colnames(AHBA_MRI_merged_organized)[3] <- "AHBA_expression"
colnames(AHBA_MRI_merged_organized)[8] <- "t_value"

Exporting as csv AHBA_MRI_merged_organized

setwd("/Users/tammyray/Desktop/aaron_lab_2024/CSV_data_sheets")
write_csv(AHBA_MRI_merged_organized, "AHBA_MRI_merged.csv")

Pearson correlation analysis I want to do a correlation analysis between the AHBA expression and the MRI data

Creating functions to compute correlation and p-value, created by ChatGPT

correlation_with_pvalue_pearson <- function(x, y) {
  test <- cor.test(x, y, method = "pearson")
  return(data.frame(correlation = test$estimate, p_value = test$p.value))
}

correlation_with_pvalue_spearman <- function(x, y) {
  test <- cor.test(x, y, method = "spearman")
  return(data.frame(correlation = test$estimate, p_value = test$p.value))
}

Running the correlation analysis

# Group by gene_symbol and compute correlation between AHBA_expression and Estimate
cor_results_Estimate_pearson <- AHBA_MRI_merged_organized %>%
  group_by(gene_symbol) %>%
  summarize(correlation = cor(AHBA_expression, Estimate, method = "pearson"),
            p_value = correlation_with_pvalue_pearson(AHBA_expression, Estimate)$p_value) %>%
  mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))

#Trying a spearman correlation analysis instead
cor_results_Estimate_spearman <- AHBA_MRI_merged_organized %>%
  group_by(gene_symbol) %>%
  summarize(correlation = cor(AHBA_expression, Estimate, method = "spearman"),
            p_value = cor.test(AHBA_expression, Estimate, method = "spearman")$p.value) %>%
  mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))

# Doing the same thing for the t value
# Pearson correlation
cor_results_t_value_pearson <- AHBA_MRI_merged_organized %>%
  group_by(gene_symbol) %>%
  summarize(correlation = cor(AHBA_expression, t_value, method = "pearson"),
            p_value = correlation_with_pvalue_pearson(AHBA_expression, t_value)$p_value) %>%
  mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))

#Spearman correlation
cor_results_t_value_spearman <- AHBA_MRI_merged_organized %>%
  group_by(gene_symbol) %>%
  summarize(correlation = cor(AHBA_expression, t_value, method = "spearman"),
            p_value = cor.test(AHBA_expression, t_value, method = "spearman")$p.value) %>%
  mutate(in_16p_locus = ifelse(gene_symbol %in% sixteen_p_11.2_genes, "Yes", "No"))

Exporting the correlation analysis dataframes to CSV files

setwd("/Users/tammyray/Desktop/aaron_lab_2024/CSV_data_sheets")
write_csv(cor_results_Estimate_pearson, "AHBA_MRI_correlation_Estimate_Pearson.csv")
write_csv(cor_results_Estimate_spearman, "AHBA_MRI_correlation_Estimate_Spearman.csv")
write_csv(cor_results_t_value_pearson, "AHBA_MRI_correlation_t_value_Pearson.csv")
write_csv(cor_results_t_value_spearman, "AHBA_MRI_correlation_t_value_Spearman.csv")

Now, I want to visualize the correlation data

#Scatterplot showing relationship between p value and correlation, not super useful but educational for me!
ggplot(cor_results_t_value_spearman, aes(x=p_value, y=correlation, color=in_16p_locus)) +
  geom_point() +
  labs(title = "Spearman correlation of t-value",
       x = "p value",
       y = "correlation") +
  theme_minimal() + 
  geom_vline(aes(xintercept = 0.05))


#making a density curve instead?
ggplot(cor_results_t_value_spearman, aes(x=correlation, color=in_16p_locus)) +
  geom_density() +
  labs(title = "Spearman correlation of t-value",
       x = "Correlation Coefficient",
       y = "Density") +
  theme_minimal()


# making a histogram instead
ggplot(cor_results_t_value_spearman, aes(x= abs(correlation), fill=in_16p_locus)) +
  geom_histogram(position = "identity", alpha = 0.6) +
  labs(title = "Spearman correlation of t-value",
       x = "Absolute Value of Correlation Coefficient",
       y = "Frequency") +
  theme_minimal() +
  xlim(0, 0.6) + ylim(0, 8)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 4 rows containing missing values or values outside the scale range (`geom_bar()`).

ggplot(cor_results_Estimate_spearman, aes(x=abs(correlation), fill=in_16p_locus)) +
  geom_histogram(position = "identity", alpha = 0.6) +
  labs(title = "Spearman correlation of Estimate(~effect size)",
       x = "Absolute Value of Correlation Coefficient",
       y = "Frequency") +
  theme_minimal() +
  xlim(0, 0.6) + ylim(0, 8)
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 4 rows containing missing values or values outside the scale range (`geom_bar()`).

Now I want to plot the data

library("ggpubr")
library(plotly)
#Making a huge plot with a lot of little plots inside (courtesy of facet_wrap) of all genes
scatter_plot_estimate <- ggplot(AHBA_MRI_merged_organized, aes(x = AHBA_expression, y = Estimate, color = region)) +
  geom_point(size = 0.1) + 
  geom_smooth(method = "lm", se = FALSE, color = "blue", linewidth = 0.5) +  # Add a line of best fit (linear regression)
  labs(title = "Scatter plots of AHBA Expression vs Estimate for all Genes",
       x = "AHBA Expression",
       y = "Estimate") +
  facet_wrap(~ gene_symbol, scales = "free") +  # Separate plots for each gene
  theme_minimal() +
  xlim(0, 1) + ylim(-0.7, 0.7) #+
  stat_cor(aes(label = paste(..r.label.., sep = "~`,`~")), 
         method = "pearson", label.x = 3, label.y = 0)  # Add correlation coefficients to the plot
mapping: label = ~paste(..r.label.., sep = "~`,`~") 
geom_text: parse = TRUE, na.rm = FALSE
stat_cor: label.x.npc = left, label.y.npc = top, label.x = 3, label.y = 0, label.sep = , , method = pearson, alternative = two.sided, output.type = expression, digits = 2, r.digits = 2, p.digits = 2, r.accuracy = NULL, p.accuracy = NULL, cor.coef.name = R, na.rm = FALSE
position_identity 
# Convert to a plotly object
interactive_plot_estimate <- ggplotly(scatter_plot_estimate, tooltip = c("text"))
`geom_smooth()` using formula = 'y ~ x'
interactive_plot_estimate # Display the interactive plot

#Doing the same plot, but for t-value
scatter_plot_t_value <- ggplot(AHBA_MRI_merged_organized, aes(x = AHBA_expression, y = Estimate, color = region)) +
  geom_point(size = 0.1) + 
  geom_smooth(method = "lm", se = FALSE, color = "blue", linewidth = 0.5) +  # Add a line of best fit (linear regression)
  labs(title = "Scatter plots of AHBA Expression vs Estimate for all Genes",
       x = "AHBA Expression",
       y = "Estimate") +
  facet_wrap(~ gene_symbol, scales = "free") +  # Separate plots for each gene
  theme_minimal() +
  stat_cor(aes(label = paste(..r.label.., sep = "~`,`~")), 
           method = "pearson", label.x = 3, label.y = 0)  # Add correlation coefficients to the plot

# Convert to a plotly object
interactive_plot_t_value <- ggplotly(scatter_plot_t_value, tooltip = c("text"))
`geom_smooth()` using formula = 'y ~ x'
interactive_plot_t_value # Display the interactive plot

Doing the above plotting for the 16p genes only

# Doing the above plotting for the NON 16p genes ----
AHBA_MRI_merged_organized_NOT_IN_16p_locus <- AHBA_MRI_merged_organized %>% filter(in_16p_region == "No")

scatter_plot_NOT_16p_genes <- ggplot(AHBA_MRI_merged_organized_NOT_IN_16p_locus, aes(x = AHBA_expression, y = Estimate, color = region)) +
  geom_point(size = 0.1) + 
  geom_smooth(method = "lm", se = FALSE, color = "blue", linewidth = 0.5, fullrange = TRUE) +  # Add a line of best fit (linear regression)
  labs(title = "Scatter plots of AHBA Expression vs Estimate for Genes NOT in 16p locus",
       x = "AHBA Expression",
       y = "Estimate") +
  facet_wrap(~ gene_symbol, scales = "free") +  # Separate plots for each gene
  theme_minimal() +
  stat_cor(aes(label = paste(..r.label.., sep = "~`,`~")), 
           method = "pearson", label.x = 3, label.y = 0) + # Add correlation coefficients to the plot
  xlim(0, 1)  # Adjust axis limits
# Convert to a plotly object
interactive_plot_NOT_16p_genes <- ggplotly(scatter_plot_NOT_16p_genes, tooltip = c("text"))

# Display the interactive plot
interactive_plot_NOT_16p_genes

Adding correlation coefficiencies and p values to plots 1. Making new dataframw with facet labels

# Merge main data with correlation results
plot_data_t_value_spearman <- AHBA_MRI_merged_organized %>%
  left_join(cor_results_t_value_spearman, by = "gene_symbol") %>% # Merge by gene_symbol
  mutate(facet_label = paste0(gene_symbol, "\n", 
                              "| R: ", round(correlation, 2), 
                              ", p: ", round(p_value, 3)))
  1. replotting data
ggplot(plot_data_t_value_spearman, aes(x = AHBA_expression, y = t_value, color = region)) +
  geom_point(size = 0.1) + 
  geom_smooth(method = "lm", se = FALSE, color = "blue", linewidth = 0.5, fullrange = TRUE) +  # Add a line of best fit (linear regression)
  labs(title = "Scatter plots of AHBA Expression vs t-value for all Genes",
       x = "AHBA Expression",
       y = "t-value") +
  facet_wrap(~ facet_label, scales = "free") +  # Use the custom facet label
  theme_minimal() +
  xlim(0, 1) #+ ylim(-0.7, 0.7)  # Adjust axis limits
LS0tCnRpdGxlOiAiMTZwMTEuMiBDTlYgcHJvamVjdCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ21kK09wdGlvbitJKi4KCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ21kK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuIAoKVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLgoKSW1wb3J0IG5lY2Vzc2FyeSBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCkltcG9ydGluZyBuZWNlc2FyeSBDU1YgZmlsZXMKYGBge3J9CiNTZXR0aW5nIHdvcmtpbmcgZGlyZWN0b3J5CnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9BYXJvbl8xNnBfSW1hZ2luZ19UcmFuc2NyaXB0b21pY3MvQ1NWX2RhdGFfc2hlZXRzL3RyYW5zY3JpcHRvbWljX2RhdGFzaGVldHMiKQojSW1wb3J0aW5nIHRyYW5jcmlwdG9taWMgZGF0YXNkZXRzClRhbGtvd3NraTIwMTQgPC0gcmVhZC5jc3YoIlRhbGtvd3NraV8yMDE0X1RhYmxlUzNfSHVtYW5fRGVsLmNzdiIpClVycmVzdGkyMDIxXzNNX29yZ2Fub2lkIDwtIHJlYWQuY3N2KCJVcnJlc3RpLTIwMjFfREVHLTNNLWNvcnRpY2FsLW9yZ2Fub2lkLmNzdiIpClJvdGgyMDIwIDwtICByZWFkLmNzdigiUm90aF8yMDIwX0RFRy1oSVBTQy1uZXVyYWwtZW5kb2Rlcm1NZXNvZGVybS5jc3YiKQojSW1wb3J0aW5nIGZpbGUgY29udGFpbmluZyAxNnAxMS4yIGdlbmUgbGlzdApjaHIxNnAxMS4yX2dlbmVfbGlzdF9LdXNlbmRhMjAxNSA8LSAgcmVhZC5jc3YoIkt1c2VuZGFfMjAxNV9UYWJsZVMxXzE2cDExLjJfZ2VuZV9saXN0LmNzdiIpCiNDcmVhdGluZyBhIHZlY3RvciBvZiBhbGwgZ2VuZXMgaW4gdGhlIDE2cDExLjIgY2hyb21vc29tYWwgcmVnaW9uCnNpeHRlZW5QMTEuMl9nZW5lcyA8LSBjaHIxNnAxMS4yX2dlbmVfbGlzdF9LdXNlbmRhMjAxNSRHZW5lLnN5bWJvbAoKYGBgCgpNb2RpZnlpbmcgZGF0YWZyYW1lcywgc3VjaCB0aGF0IHRoZXkgaGF2ZSB0aGUgc2FtZSBjb2x1bW4gbmFtZXMsIGluIG9yZGVyIHRvIGNvbWJpbmUgdGhlbQoKMS4gVXJlc3RpIDIwMjEgY29ydGljYWwgb3JnYW5vaWRzIGRhdGEKYGBge3J9ClVycmVzdGkyMDIxXzNNX29yZ2Fub2lkX3RpZHkgPC0gVXJyZXN0aTIwMjFfM01fb3JnYW5vaWQgJT4lCiAgI3JlbW92ZSBjb2x1bW5zIHRoYXQgaSBkbyBub3QgbmVlZAogIHNlbGVjdCgtYygiR2VuZS5CaW90eXBlIiwgImxvZzIuRkMuLkRVUC52cy5ERUwiLCAiUC52YWx1ZS4uRFVQLnZzLkRFTCIsICJGRFIuYWRqdXN0ZWQuUC52YWx1ZS4uRFVQLnZzLkRFTCIsICJsb2cyLkZDLi5EVVAudnMuQ1RMIiwKICAgICAgICAgICAgIlAudmFsdWUuLkRVUC52cy5DVEwiLCAiRkRSLmFkanVzdGVkLlAudmFsdWUuLkRVUC52cy5DVEwiLCAiRkRSLmFkanVzdGVkLlAudmFsdWUuLkRFTC52cy5DVEwiKSkgJT4lCiAgI3JlbmFtZSBjb2x1bW5zIHRvIHRoZSBzdGFuZGFyZGl6ZWQgbmFtZXMgSSBkZWNpZGVkIG9uCiAgcmVuYW1lKCJnZW5lX25hbWUiID0gIkhHTkMuU3ltYm9sIiwKICAgICAgICAgImxvZzJfZm9sZF9jaGFuZ2UiID0gImxvZzIuRkMuLkRFTC52cy5DVEwiLAogICAgICAgICAicF92YWx1ZSIgPSAiUC52YWx1ZS4uREVMLnZzLkNUTCIsCiAgICAgICAgICJnZW5lX2Rlc2NyaXB0aW9uIiA9ICJEZXNjcmlwdGlvbiIsIAogICAgICAgICAiRU5TRU1CTF9JRCIgPSAiRU5TRU1CTC5JRCIpICU+JQogICNhZGQgYSBjb2x1bW4gZm9yIHRoZSBkYXRhIHNvdXJjZQogIG11dGF0ZSggInNhbXBsZV90eXBlIiA9ICJjb3J0aWNhbCBvcmdhbm9pZCIsICJkYXRhX3NvdXJjZSIgPSAiVXJyZXN0aSBldCBhbC4gMjAyMSIsICJQcmVzZW50LmluLnRoZS4xNnAxMS4yLlJlZ2lvbiIgPSAiIikgJT4lCiAgI3Jlb3JkZXIgY29sdW1ucyBzbyB0aGF0IHRoZSBlbnNlbWJsZV9JRCBjb2x1bW4sIHdoaWNoIG5vdCBhbGwgZGF0YWZyYW1lcyB3aWxsIGhhdmUsIGlzIGF0IHRoZSBlbmQKICByZWxvY2F0ZSgiRU5TRU1CTF9JRCIsIC5hZnRlciA9ICJkYXRhX3NvdXJjZSIpCgpgYGAKCjIuIFJvdGggMjAyMCBkYXRhCmBgYHtyfQpSb3RoMjAyMF90aWR5IDwtIFJvdGgyMDIwICU+JQogICMgcmVtb3ZlIGNvbHVtbnMgdGhhdCBJIGRvIG5vdCBuZWVkCiAgc2VsZWN0KC1jKCJTRkFSSS5HZW5lLlNjb3JlIiwgIlNGQVJJLkdlbmUuU2NvcmUuQ2F0ZWdvcnkiLCAiaHR0cHMuLi5nZW5lLnNmYXJpLm9yZy5hYm91dC5nZW5lLnNjb3JpbmcuY3JpdGVyaWEuIikpICU+JQogICNyZW5hbWUgY29sdW1ucyB0byB0aGUgc3RhbmRhcmRpemVkIG5hbWVzIEkgZGVjaWRlZCBvbgogIHJlbmFtZSgiZ2VuZV9uYW1lIiA9ICJYMTZwMTEuMi5ERS5HZW5lcyIsCiAgICAgICAgICJsb2cyX2ZvbGRfY2hhbmdlIiA9ICJMb2cyLkZvbGQuQ2hhbmdlLi5Qb3NpdGl2ZS52YWx1ZXMuYXJlLnVwcmVndWxhdGVkLmluLkRFTC4iLAogICAgICAgICAicF92YWx1ZSIgPSAiQWRqdXN0ZWQuUC5WYWx1ZSIpICU+JQogICNhZGQgY29sdW1ucyBmb3IgdGhlIGRhdGEgc291cmNlLCBzYW1wbGUgdHlwZSwgYW5kIGV4dHJhcyB0byBtYXRjaCB0aGUgYWJvdmUgZGF0YXNldAogIG11dGF0ZSgiZ2VuZV9kZXNjcmlwdGlvbiIgPSAiIiwgInNhbXBsZV90eXBlIiA9ICJoSVBTQyIsICJkYXRhX3NvdXJjZSIgPSAiUm90aCBldCBhbC4gMjAyMCIsICJFTlNFTUJMX0lEIiA9ICIiKSAlPiUKICAjcmVvcmRlciBjb2x1bW5zIHRvIG1hdGNoIHRoZSBvdGhlciBkYXRhZnJhbWVzCiAgcmVsb2NhdGUoImdlbmVfZGVzY3JpcHRpb24iLCAuYWZ0ZXIgPSAiZ2VuZV9uYW1lIikgJT4lCiAgcmVsb2NhdGUoIlByZXNlbnQuaW4udGhlLjE2cDExLjIuUmVnaW9uIiwgLmFmdGVyID0gIkVOU0VNQkxfSUQiKQoKYGBgCgozLiBUYWxrb3dza2kgMjAxNCBkYXRhCmBgYHtyfSAKVGFsa293c2tpMjAxNF90aWR5IDwtIFRhbGtvd3NraTIwMTQgJT4lIAogIHNlbGVjdCgtYygiR2VuZUluZm8iLCAiQ2hyIiwgIlN0YXJ0IiwgIlN0b3AiKSkgJT4lCiAgI3NlbGVjdCgtYygiR2VuZUluZm8iLCAiQ2hyIiwgIlN0YXJ0IiwgIlN0b3AiKSkgJT4lCiAgI1RyYW5zZm9ybWluZyB0aGUgZm9sZGNoYW5nZSB0byBsb2cyIGZvbGRjaGFuZ2UKICBtdXRhdGUoIkZvbGRDaGFuZ2UiID0gbG9nMihGb2xkQ2hhbmdlKSkgJT4lCiAgI3JlbmFtZSBjb2x1bW5zIHRvIHRoZSBzdGFuZGFyZGl6ZWQgbmFtZXMgSSBkZWNpZGVkIG9uCiAgcmVuYW1lKCJnZW5lX25hbWUiID0gIkdlbmVJRCIsCiAgICAgICAgICJsb2cyX2ZvbGRfY2hhbmdlIiA9ICJGb2xkQ2hhbmdlIiwKICAgICAgICAgInBfdmFsdWUiID0gInBlcm1QdmFsX0RlbCIpICU+JQogICNhZGQgY29sdW1ucyBmb3IgdGhlIGRhdGEgc291cmNlLCBzYW1wbGUgdHlwZSwgYW5kIGV4dHJhcyB0byBtYXRjaCB0aGUgYWJvdmUgZGF0YXNldAogIG11dGF0ZSgiZ2VuZV9kZXNjcmlwdGlvbiIgPSAiIiwgInNhbXBsZV90eXBlIiA9ICJoTENMIiwgImRhdGFfc291cmNlIiA9ICJUYWxrb3dza2kgZXQgYWwuIDIwMTQiLCAiRU5TRU1CTF9JRCIgPSAiIiwgIlByZXNlbnQuaW4udGhlLjE2cDExLjIuUmVnaW9uIiA9ICIiKSAlPiUKICAjcmVvcmRlciBjb2x1bW5zIHRvIG1hdGNoIHRoZSBvdGhlciBkYXRhZnJhbWVzCiAgcmVsb2NhdGUoImdlbmVfZGVzY3JpcHRpb24iLCAuYWZ0ZXIgPSAiZ2VuZV9uYW1lIikgJT4lCiAgcmVsb2NhdGUoInBfdmFsdWUiLCAuYWZ0ZXIgPSAibG9nMl9mb2xkX2NoYW5nZSIpCgpgYGAKClBvdGVudGlhbCBuZXh0IHN0ZXA6IEkgdHJpZWQgdG8gYWRkIGluIHRoZSBlbnNlbWJsIElEIGZvciB0aGUgVGFsa293c2tpIDIwMTQgZGF0YSwgYnV0IHRoYXQgZGF0YXNldCB1c2VkIGFuIG9sZCByZWZyZW5jZSB0cmFuc2NyaXB0b21lIGFuZCBzbywgdXNpbmcgdGhlIApjaHJvbW9zb21hbCBzdGFydCBhbmQgc3RvcCBwb3NpdGlvbnMgYW5kIGNocm9tb3NvbWUgbnVtYmVyLCBJIHdhcyB1bmFibGUgdG8gZmluZCB0aGUgZW5zZW1ibCBJRCBmb3IgdGhlIGdlbmVzIGluIHRoYXQgZGF0YXNldC4gSQoKCgoKTm93LCBJIHdhbnQgdG8gZmlsbCBpbiB0aGUgIlByZXNlbnQuaW4udGhlLjE2cDExLjIuUmVnaW9uIiBjb2x1bW4gZm9yIHRoZSBERUdfYWxsX3RpbWVwb2ludHNfb3JnYW5vaWRfVXJyZXN0aTIwMjFfbW9kaWZpZWRfY29sdW1ucyBkYXRhZnJhbWUuIApgYGB7cn0KIyBUaGUgdmVjdG9yIHNpeHRlZW5QMTEuMl9nZW5lcyBpcyBhIHZlY3RvciBjb250YWluaW5nIGFsbCBnZW5lcyBsb2NhdGVkIGluIHRoZSAxNnAxMS4yIGNocm9tb3NvbWFsIHJlZ2lvbgojIEkgd2FudCB0byBjaGFuZ2UgdGhlIHZhbHVlIG9mIHRoZSAiUHJlc2VudC5pbi50aGUuMTZwMTEuMi5SZWdpb24iIGNvbHVtbiB0byAiWWVzIiBpZiB0aGUgZ2VuZSBuYW1lIGlzIGluIHRoZSB2ZWN0b3IsIGFuZCAiTm8iIGlmIGl0IGlzIG5vdAoKVXJyZXN0aTIwMjFfM01fb3JnYW5vaWRfdGlkeSRQcmVzZW50LmluLnRoZS4xNnAxMS4yLlJlZ2lvbiA8LQogIGlmZWxzZShVcnJlc3RpMjAyMV8zTV9vcmdhbm9pZF90aWR5JGdlbmVfbmFtZSAlaW4lIHNpeHRlZW5QMTEuMl9nZW5lcywgIlllcyIsICJObyIpClJvdGgyMDIwX3RpZHkkUHJlc2VudC5pbi50aGUuMTZwMTEuMi5SZWdpb24gPC0KICBpZmVsc2UoUm90aDIwMjBfdGlkeSRnZW5lX25hbWUgJWluJSBzaXh0ZWVuUDExLjJfZ2VuZXMsICJZZXMiLCAiTm8iKQpUYWxrb3dza2kyMDE0X3RpZHkkUHJlc2VudC5pbi50aGUuMTZwMTEuMi5SZWdpb24gPC0KICBpZmVsc2UoVGFsa293c2tpMjAxNF90aWR5JGdlbmVfbmFtZSAlaW4lIHNpeHRlZW5QMTEuMl9nZW5lcywgIlllcyIsICJObyIpCgpgYGAKCgpOb3cgSSBjb21iaW5lIGFsbCAzIG9yZ2FuaXplZCBkYXRhZnJhbWVzIGludG8gMSBkYXRhZnJhbWUKYGBge3J9CmFsbF9ERUdfZGF0YSA8LSByYmluZChVcnJlc3RpMjAyMV8zTV9vcmdhbm9pZF90aWR5LCBSb3RoMjAyMF90aWR5LCBUYWxrb3dza2kyMDE0X3RpZHkpCgojIE5vdywgSSB3YW50IHRvIGxvb2sgYXQgdGhlIGdlbmVzIGluIHRoZSAxNnAxMS4yIHJlZ2lvbiBvbmx5LCBmcm9tIHRoZSBhbGwgREVHIGRhdGEuIFNvIEkgd2lsbCBmaWx0ZXIgdGhlIGFsbF9ERUdfZGF0YSBkYXRhZnJhbWUgdG8gb25seSBpbmNsdWRlIHRob3NlIGdlbmVzCmFsbF9ERUdfMTZwX2dlbmVzIDwtIGFsbF9ERUdfZGF0YSAlPiUKICBmaWx0ZXIoUHJlc2VudC5pbi50aGUuMTZwMTEuMi5SZWdpb24gPT0gIlllcyIpCgpgYGAKCgpObyBJIHdpbGwgZG8gYSBtZXRhYW5hbHlzaXMgdG8gY29tYmluZSBldmVyeSBpbnN0YW5jZSBvZiBhIGdlbmUgaW50byBvbmUgcm93LCBzbyB0aGF0IEkgY2FuIHNlZSBhbGwgdGhlIGRhdGEgZm9yIGVhY2ggZ2VuZSBpbiBvbmUgcm93CkxvZyBmb2xkIGNoYW5nZSBpcyB3ZWlnaHRlZCBieSBwLXZhbHVlCnAgdmFsdWVzIGFyZSBjb21iaW5lZCB3aXRoIGZpc2hlcnMgZXhhY3QgdGVzdApgYGB7cn0KbWV0YV9hbmFseXNpc19hbGxfREVHX2RhdGEgPC0gYWxsX0RFR19kYXRhICU+JQogIGdyb3VwX2J5KGdlbmVfbmFtZSkgJT4lCiAgc3VtbWFyaXplKGNvbWJpbmVkX2xvZzJfZm9sZF9jaGFuZ2UgPSBzdW0obG9nMl9mb2xkX2NoYW5nZSAvIChwX3ZhbHVlICsgMWUtOCkpIC8gc3VtKDEgLyAocF92YWx1ZSArIDFlLTgpKSwgICMgV2VpZ2h0ZWQgbG9nRkMgdXNpbmcgcC12YWx1ZXMuCiAgICAgICAgICAgICMgQSBzbWFsbCBjb25zdGFudCAoMWUtOCkgaXMgYWRkZWQgdG8gYXZvaWQgZGl2aXNpb24gYnkgemVybyBpZiB0aGVyZSBhcmUgdmVyeSBzbWFsbCBwLXZhbHVlcy4KICAgICAgICAgICAgI2luIHRoZSBuZXh0IGxpbmUgb2YgY29kZSBJIHdpbGwgZG8gYSBmaXNoZXIgdGVzdCB0byBjb21iaW5lIHRoZSBwLXZhbHVlcwogICAgICAgICAgICBjb21iaW5lZF9wX3ZhbHVlID0gMSAtIHBjaGlzcShzdW0ocWNoaXNxKDEgLSBwX3ZhbHVlLCAxLCBsb3dlci50YWlsID0gRkFMU0UpKSwgbGVuZ3RoKHBfdmFsdWUpLCBsb3dlci50YWlsID0gRkFMU0UpKSAlPiUKICAjdGhlIGFib3ZlIGNvZGUgd2lsbCByZXR1cm4gYSBkYXRhZnJhbWUgdGhhdCBvbmx5IGNvbnRhaW5zIDMgb2YgdGhlIGNvbHVtbnMuIEluIHRoZSBuZXh0IGxpbmUgb2YgY29kZSBJIHdpbGwgYnJpbmcgdGhlIHJlc3Qgb2YgdGhlIGNvbHVtbnMgYmFjayB0byB0aGlzIG5ldyBkYXRhZnJhbWUKICBsZWZ0X2pvaW4oYWxsX0RFR19kYXRhLCBieSA9ICJnZW5lX25hbWUiKQoKCiNLZWVwIHRyYWNrIG9mIGlmIHRoZSBnZW5lIGNvbWJpbmVkIGxvZ2ZvbGRjYWhuZ2UgYW5kIHAtdmFsdWUgYXJlIGZyb20gbXVsdGlwbGUgZGF0YSBzb3VyY2VzCm1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhJG11bHRpcGxlX2RhdGFfc291cmNlcyA8LSBpZmVsc2UoZHVwbGljYXRlZChtZXRhX2FuYWx5c2lzX2FsbF9ERUdfZGF0YSRnZW5lX25hbWUpIHwgZHVwbGljYXRlZChtZXRhX2FuYWx5c2lzX2FsbF9ERUdfZGF0YSRnZW5lX25hbWUsIGZyb21MYXN0ID0gVFJVRSksICJZZXMiLCAiTm8iKQoKCiNOb3csIEkgd2FudCB0byBkZWxldGUgcm93cyB0aGF0IGhhdmUgdGhlIHNhbWUgZ2VuZSBuYW1lIGFuZCByZW1vdmUgdGhlIGNvbHVtbnMgdGhhdCBoYXZlIHRoZSBvcmlnaW5hbCBsb2cyX2ZvbGRfY2hhbmdlLCBwX3ZhbHVlLCBzYW1wbGVfdHlwZSwgYW5kIGRhdGFfc291cmNlCm1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhIDwtIG1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhICU+JQogIGRpc3RpbmN0KGdlbmVfbmFtZSwgLmtlZXBfYWxsID0gVFJVRSkgJT4lCiAgc2VsZWN0KC1jKGxvZzJfZm9sZF9jaGFuZ2UsIHBfdmFsdWUsIHNhbXBsZV90eXBlLCBkYXRhX3NvdXJjZSkpCgojVGhpcyBjb2RlIGFkZHMgYSBjb2x1bW4gY2FsbGVkIHNpZ25pZmljYW5jZSB0aGF0IHdpbGwgaW5kaWNhdGUgdGhlIGRlZ3JlZSBvZiBzaWduaWZpY2FuY2UsIGp1c3QgbGlrZSBTbXJpdGhpJ3MgY29kZQptZXRhX2FuYWx5c2lzX2FsbF9ERUdfZGF0YSA8LSBtZXRhX2FuYWx5c2lzX2FsbF9ERUdfZGF0YSAlPiUKICBtdXRhdGUoInNpZ25pZmljYW5jZSIgPSBjYXNlX3doZW4oCiAgICBjb21iaW5lZF9wX3ZhbHVlIDwgMC4wMDEgfiAiKioqIiwKICAgIGNvbWJpbmVkX3BfdmFsdWUgPCAwLjAxIH4gIioqIiwKICAgIGNvbWJpbmVkX3BfdmFsdWUgPCAwLjA1IH4gIioiLAogICAgVFJVRSB+ICIgIgogICkpCgojTm93IGkgd2lsbCBjcmVhdGUgYSBuZXcgZGF0YWZyYW1lIHdpdGggb25seSB0aGUgZ2VuZXMgdGhhdCBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYXQgY29tYmluZWQgcC12YWx1ZSA8IDAuMDAxCnNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEgPC0gbWV0YV9hbmFseXNpc19hbGxfREVHX2RhdGEgJT4lCiAgZmlsdGVyKHNpZ25pZmljYW5jZSA9PSAiKioqIikKCmBgYAoKRXhwb3J0aW5nIHRoZSBkYXRhZnJhbWVzIHRvIENTViBmaWxlcywgaWYgZGVzaXJlZAoKYGBge3J9CnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9hYXJvbl9sYWJfMjAyNC9vdXRwdXQiKQoKd3JpdGUuY3N2KFVycmVzdGkyMDIxXzNNX29yZ2Fub2lkX3RpZHksIGZpbGU9IlVycmVzdGkyMDIxXzNNX29yZ2Fub2lkX3RpZHkuY3N2IikKd3JpdGUuY3N2KFJvdGgyMDIwX3RpZHksIGZpbGU9IlJvdGgyMDIwX3RpZHkuY3N2IikKd3JpdGUuY3N2KFRhbGtvd3NraTIwMTRfdGlkeSwgZmlsZT0iVGFsa293c2tpMjAxNF90aWR5LmNzdiIpCndyaXRlLmNzdihhbGxfREVHX2RhdGEsIGZpbGU9ImFsbF9ERUdfZGF0YS5jc3YiKQp3cml0ZS5jc3YobWV0YV9hbmFseXNpc19hbGxfREVHX2RhdGEsIGZpbGU9Im1ldGFfYW5hbHlzaXNfYWxsX0RFR19kYXRhLmNzdiIpCndyaXRlLmNzdihzaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhLCBmaWxlPSJzaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhLmNzdiIpCmBgYAoKCkdlbmUgb250b2xvZ3kgYW5hbHlzaXMKSSBhbSB1c2luZyBncHJvZmlsZXIyIHRvIGRvIG15IEdPIGFuYWx5c2lzCkxvYWRpbmcgZ3Byb2ZpbGVyMiBwYWNrYWdlCmBgYHtyfQpsaWJyYXJ5KGdwcm9maWxlcjIpCmBgYAoKCkRvaW5nIEdPIGFuYWx5c2lzCmBgYHtyfQojIE1ha2luZyB2ZWN0b3Igb2YgZ2VuZXMgaW4gc2lnIGdlbmUgZGF0YWZyYW1lCmV4cF9nZW5lX2xpc3RfMV9wXzAuMDAxIDwtIHNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEkZ2VuZV9uYW1lCgojIHVzaW5nIGdvc3QgZnVuY3Rpb24gZnJtbyBncHJvZmlsZXIyIHRvIGRvIEdPIGFuYWx5c2lzCkdPX3Jlc3VsdHNfZXhwX2dlbmVfbGlzdF9wMC4wMDEgPSBnb3N0KHF1ZXJ5ID0gZXhwX2dlbmVfbGlzdF8xX3BfMC4wMDEsCiAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYXBpZW5zIiwKICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSAiZmRyIikKR09fYWxsX3Jlc3VsdHNfcDAuMDAxIDwtIEdPX3Jlc3VsdHNfZXhwX2dlbmVfbGlzdF9wMC4wMDEkcmVzdWx0ICU+JQogIHNlbGVjdCgtcGFyZW50cykKCiNwdXR0aW5nIG1ldGFkYXRhIGZyb20gR08gYW5hbHlzaXMgaW50byBhIGRhdGFmcmFtZQpHT19tZXRhX3AwLjAwMSA8LSBHT19yZXN1bHRzX2V4cF9nZW5lX2xpc3RfcDAuMDAxJG1ldGEKCgojQ3JlYXRpbmcgZ2VuZSBsaXN0cyBmb3IgdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMKVVByZWd1bGF0ZWRfc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSA8LSBzaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhICU+JQogIGZpbHRlcihjb21iaW5lZF9sb2cyX2ZvbGRfY2hhbmdlID4gMCkKVVByZWd1bGF0ZWRfZXhwX2dlbmVfbGlzdF8xX3BfMC4wMDEgPC0gVVByZWd1bGF0ZWRfc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSRnZW5lX25hbWUKCkRPV05yZWd1bGF0ZWRfc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSA8LSBzaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhICU+JQogIGZpbHRlcihjb21iaW5lZF9sb2cyX2ZvbGRfY2hhbmdlIDwgMCkKRE9XTnJlZ3VsYXRlZF9zaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhIDwtIERPV05yZWd1bGF0ZWRfc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSRnZW5lX25hbWUKCnVwX3JlZ19nZW5lcyA8LSBzaWdfZ2VuZXNfcDAuMDAxX0RFR19kYXRhICU+JSBmaWx0ZXIoY29tYmluZWRfbG9nMl9mb2xkX2NoYW5nZSA+IDApCnVwX3JlZ19nZW5lX25hbWVzIDwtIHVwX3JlZ19nZW5lcyRnZW5lX25hbWUKCiMgR08gYW5hbHlzaXMgb2YgdXByZWd1bGF0ZWQgYW5kIGRvd25yZWd1bGF0ZWQgZ2VuZXMKZ29zdHJlc19VUHJlZ3VsYXRlZCA8LSBnb3N0KHF1ZXJ5ID0gVVByZWd1bGF0ZWRfZXhwX2dlbmVfbGlzdF8xX3BfMC4wMDEsCiAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYXBpZW5zIiwKICAgICAgICAgICAgICAgY29ycmVjdGlvbl9tZXRob2QgPSAiZmRyIikKCmdvc3RyZXNfVVByZWd1bGF0ZWQgPC0gZ29zdHJlc19VUHJlZ3VsYXRlZCRyZXN1bHQKCgpnb3N0cmVzX0RPV05yZWd1bGF0ZWQgPC0gZ29zdChxdWVyeSA9IERPV05yZWd1bGF0ZWRfc2lnX2dlbmVzX3AwLjAwMV9ERUdfZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZ2FuaXNtID0gImhzYXBpZW5zIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcnJlY3Rpb25fbWV0aG9kID0gImZkciIpCgpnb3N0cmVzX0RPV05yZWd1bGF0ZWQgPC0gZ29zdHJlc19ET1dOcmVndWxhdGVkJHJlc3VsdApgYGAKCkV4cG9ydGluZyB0aGUgR08gYW5hbHlzaXMgZGF0YWZyYW1lcyB0byBDU1YgZmlsZXMsIGlmIGRlc2lyZWQKYGBge3J9CnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9hYXJvbl9sYWJfMjAyNC9vdXRwdXQiKQp3cml0ZS5jc3YoZ29zdHJlc19yZXN1bHRzLCBmaWxlPSIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9BYXJvbl8xNnBfSW1hZ2luZ19UcmFuc2NyaXB0b21pY3Mvb3V0cHV0L0dPXzE2cDExLjItREVHc19wMC4wMDFfZmRyLWNvcnJlY3Rpb25zLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKCmBgYAoKCk5PVywgd2UgZ2VuZXJhdGUgbWFwIG9mIG91ciBzaWduaWZpY2FudCBnZW5lcyB0byBBSEJBIHNwYXRpYWwgbWFwCgoKRmlyc3QsIHJlYWQgaW4gdGhlIGRhdGEKYGBge3J9CkFIQkEgPC0gcmVhZF90c3YoIi9Vc2Vycy90YW1teXJheS9EZXNrdG9wL0Fhcm9uXzE2cF9JbWFnaW5nX1RyYW5zY3JpcHRvbWljcy9DU1ZfZGF0YV9zaGVldHMvQWxsZW5IQkFfREtfRXhwcmVzc2lvbk1hdHJpeC50c3YiKQojIE5vdywgSSB3YW50IHRvIGNjaGFuZ2UgdGhlIGNvbHVtbiBoZWFkZXIgb2YgdGhlIGZpcnN0IGNvbHVtbiBvZiB0aGUgQUhCQSBkYXRhZnJhbWUgdG8gZ2VuZV9zeW1ib2wKY29sbmFtZXMoQUhCQSlbMV0gPC0gImdlbmVfc3ltYm9sIgoKYGBgCgoKTWFwcGluZyBvdXIgc2lnbmlmaWNhbnQgZ2VuZXMgdG8gdGhlIEFIQkEgZGF0YXNldApgYGB7cn0KI0NyZWF0aW5nIHZlY3RvciBvZiBnZW5lIG5hbWVzIGluIG91ciBleHBlcmltZW50YWwgZ3JvdXBzCnNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEgI2RhdGFmcmFtZSBjb250YWluaW5nIGFsbCBzaWduaWZpY2FudCBnZW5lcwpzaWdfZ2VuZV9saXN0IDwtIHNpZ19nZW5lc19wMC4wMDFfREVHX2RhdGEkZ2VuZV9uYW1lICN2ZWN0b3Igb2YgYWxsIHNpZ25pZmljYW50IGdlbmVzIG5hbWVzCnNpeHRlZW5QMTEuMl9nZW5lcyAjZGF0YWZyYW1lIGNvbnRhaW5pbmcgYWxsIGdlbmVzIGluIDE2cDExLjIgbG9jdXMKc2l4dGVlbl9wXzExLjJfZ2VuZXMgPC0gY2hyMTZwMTEuMl9nZW5lX2xpc3RfS3VzZW5kYTIwMTUkR2VuZS5zeW1ib2wgI3ZlY3RvciBvZiBhbGwgZ2VuZXMgaW4gMTZwIGxvY3VzCgpBSEJBX3NpZ19nZW5lcyA8LSBBSEJBICU+JSBmaWx0ZXIoZ2VuZV9zeW1ib2wgJWluJSBzaWdfZ2VuZV9saXN0KQoKI05PVEU6IG5vdCBhbGwgc2lnIGdlbmVzIG1hcHBlZCB0byBBSEJBIGRhdGFzZXQuIEhlcmUgaXMgYSBsaXN0IG9mIHRoZW0gc28gSSBjYW4gdHJvdWJsZXNob290IGxhdGVyCmdlbmVzX25vdF9tYXBwZWQgPC0gc2lnX2dlbmVfbGlzdFshKHNpZ19nZW5lX2xpc3QgJWluJSBBSEJBX3NpZ19nZW5lcyRnZW5lX3N5bWJvbCldCmBgYApOT1RFOiBPbmx5IDg3IG9mIHRoZSAxMzIgZ2VuZXMgbWFwcGVkIHRvIHRoZSBBSEJBIGRhdGFzZXQKCgpUaWR5aW5nIHRoZSBBSEJBIHN1YnNldCBkYXRhZnJhbWUgd2l0aCBzaWduaWZpY2FudCBnZW5lcyBvbmx5CmBgYHtyfQpBSEJBX3NpZ19nZW5lc19waXZvdCA8LSBBSEJBX3NpZ19nZW5lcyAlPiUKICAjcmVtb3ZlIHRoZSAiQXZlcmFnZSBkb25vciBjb3JyZWxhdGlvbiB0byB0aGUgbWVkaWFuIiBjb2x1bW4KICBzZWxlY3QoLSJBdmVyYWdlIGRvbm9yIGNvcnJlbGF0aW9uIHRvIG1lZGlhbiIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLWdlbmVfc3ltYm9sLCBuYW1lc190byA9ICJyZWdpb24iLCB2YWx1ZXNfdG8gPSAiZXhwcmVzc2lvbiIpICU+JQogICNhZGRpbmcgYSBjb2x1bW4gZm9yIGlmIGdlbmUgaXMgaW4gdGhlIDE2cCByZWdpb24KICBtdXRhdGUoaW5fMTZwX3JlZ2lvbiA9IGlmZWxzZShnZW5lX3N5bWJvbCAlaW4lIHNpeHRlZW5fcF8xMS4yX2dlbmVzLCAiWWVzIiwgIk5vIikpICU+JQogICMgQWRkaW5nIGEgY29sdW1uIGZvciBpZiBnZW5lIGlzIHVwIG9yIGRvd25yZWd1bGF0ZWQKICBtdXRhdGUodXByZWcgPSBpZmVsc2UoZ2VuZV9zeW1ib2wgJWluJSB1cF9yZWdfZ2VuZV9uYW1lcywgIlllcyIsICJObyIpKQoKYGBgCgoKR0dwbG90IHRvIHZpc3VhbGl6ZSB0aGUgZGF0YQpgYGB7cn0KIyBWaXN1YWxpemluZyBleHByZXNzaW9uIGRhdGEgb2Ygc2lnbmlmaWNhbnQgZ2VuZXMKZ2dwbG90KEFIQkFfc2lnX2dlbmVzX3Bpdm90LCBhZXMoeD1leHByZXNzaW9uLCB5PXJlZ2lvbiwgc2hhcGU9aW5fMTZwX3JlZ2lvbiwgY29sb3I9Z2VuZV9zeW1ib2wpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGxhYnModGl0bGUgPSAicmVnaW9uYWwgZXhwcmVzc2lvbiBvZiBzaWduaWZpY2FudCBnZW5lcyBmcm9tIDE2cCBkZWwgbWV0YS1hbmFseXNpcyIsIHggPSAiUmF3IEV4cHJlc3Npb24iLCB5ID0gIkJyYWluIFJlZ2lvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogICNJIHdpbGwgbWFrZSB0aGUgbGVnZW5kIHNtYWxsZXIgYW5kIHB1dCBpdCB1bmRlcm5lYXRoIHRoZSBncmFwaCAgYmVjYXVzZSBpdCBpcyB0b28gYmlnCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3I9Im5vbmUiKQoKIyBzYW1lIHBsb3QgYnV0IGFlc3RoZXRpY3Mgb25seSBmb3IgZ2VuZXMgaW4gMTZwIHJlZ2lvbgpnZ3Bsb3QoQUhCQV9zaWdfZ2VuZXNfcGl2b3QsIGFlcyh4PWV4cHJlc3Npb24sIHk9cmVnaW9uLCBjb2xvcj1pbl8xNnBfcmVnaW9uKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBsYWJzKHRpdGxlID0gInJlZ2lvbmFsIGV4cHJlc3Npb24gb2Ygc2lnbmlmaWNhbnQgZ2VuZXMgZnJvbSAxNnAgZGVsIG1ldGEtYW5hbHlzaXMiLCB4ID0gIlJhdyBFeHByZXNzaW9uIiwgeSA9ICJCcmFpbiBSZWdpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICAjSSB3aWxsIG1ha2UgdGhlIGxlZ2VuZCBzbWFsbGVyIGFuZCBwdXQgaXQgdW5kZXJuZWF0aCB0aGUgZ3JhcGggIGJlY2F1c2UgaXQgaXMgdG9vIGJpZwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSAKCgpnZ3Bsb3QoQUhCQV9zaWdfZ2VuZXNfcGl2b3QsIGFlcyh4PWV4cHJlc3Npb24sIHk9cmVnaW9uLCBjb2xvcj11cHJlZykpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgbGFicyh0aXRsZSA9ICJyZWdpb25hbCBleHByZXNzaW9uIG9mIHNpZ25pZmljYW50IGdlbmVzIGZyb20gMTZwIGRlbCBtZXRhLWFuYWx5c2lzIiwgeCA9ICJSYXcgRXhwcmVzc2lvbiIsIHkgPSAiQnJhaW4gUmVnaW9uIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgI0kgd2lsbCBtYWtlIHRoZSBsZWdlbmQgc21hbGxlciBhbmQgcHV0IGl0IHVuZGVybmVhdGggdGhlIGdyYXBoICBiZWNhdXNlIGl0IGlzIHRvbyBiaWcKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgCmBgYAoKCk5vdywgd2Ugd2FudCB0byB3b3JrIHdpdGggdGhlIG5vcm1hbGl6ZWQgQUhCQSB2YWx1ZXMuIFRoZXkgYXJlIGluIGEgbWF0bGFiIGZpbGUsIHNvIGZpcnN0IEkgd2lsbCBuZWVkIHRvIGNvbnZlcnQgdGhlIG1hdGxhYiBmaWxlIHRvIHNvbWV0aGluZyBSIGNhbiByZWFkLCB3aXRoIHRoZSBSLm1hdGxhYiBwYWNrYWdlLiAKTk9URTogVGhlIFIubWF0bGFiIHBhY2thZ2UgZG9lcyBub3Qga2VlcCBjb2x1bW4gbmFtZXMgb2YgdGhlIG9yaWdpbmFsIGRhdGEgd2hlbiBjb252ZXJ0aW5nIHRoaW5ncywgc28gSSBoYWQgdG8gYWRkIHRoZW0gYmFjayBpbi4KCkZpcnN0LCBsb2FkIGxpYnJhcmllcwpgYGB7cn0KbGlicmFyeShSLm1hdGxhYikKYGBgCgpTZWNvbmQsIGxvYWQgaW4gcmVsZXZhbnQgZmlsZXMKYGBge3J9CnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9BYXJvbl8xNnBfSW1hZ2luZ19UcmFuc2NyaXB0b21pY3MiKQpBSEJBX25vcm1lZCA8LSByZWFkTWF0KCJST0l4R2VuZV9hcGFyY2FzZWdfSU5ULm1hdCIpCgpzZXR3ZCgiL1VzZXJzL3RhbW15cmF5L0Rlc2t0b3AvQWFyb25fMTZwX0ltYWdpbmdfVHJhbnNjcmlwdG9taWNzL0NTVl9kYXRhX3NoZWV0cyIpCnJlZ2lvbl9hcnJheSA8LSByZWFkX2NzdigiUmVnaW9uX2xhYmVsc19mb3JfYXBhcmNhc2VnX3BhcmNlbGxhdGlvbi5jc3YiLCBjb2xfbmFtZXMgPSBGQUxTRSkKYGBgCgpUaWR5aW5nIHVwIHRoZSBBSEJBX25vcm1lZCBkYXRhZnJhbWUKYGBge3J9CkFIQkFfcGFyY2VsX2V4cHJlc3Npb24wIDwtIGFzLmRhdGEuZnJhbWUoQUhCQV9ub3JtZWQkcGFyY2VsRXhwcmVzc2lvbikKIyBHZXR0aW5nIGxpc3Qgb2YgZ2VuZSBuYW1lcyAKYXJyYXlfZ2VuZV9uYW1lcyA8LSB1bmxpc3QoQUhCQV9ub3JtZWQkcHJvYmVJbmZvcm1hdGlvbltbMl1dKQojIEZpcnN0IGkgbmVlZCB0byBlZGl0IG15IGFycmF5X2dlbmVfbmFtZXMgdG8gYWRkIGEgMCBhcyB0aGUgZmlyc3QgaXRlbSBpbiBteSBhcnJheQphcnJheV9nZW5lX25hbWVzIDwtIGMoMCwgYXJyYXlfZ2VuZV9uYW1lcykKIyBOb3csIEkgd2FudCB0byByZW5hbWUgdGhlIGNvbHVtbnMgb2YgdGhlIEFIQkFfcGFyY2VsX2V4cHJlc3Npb24gZGF0YWZyYW1lIHRvIHRoZSBnZW5lIG5hbWVzIGluIGFycmF5X2dlbmVfbmFtZXMKY29sbmFtZXMoQUhCQV9wYXJjZWxfZXhwcmVzc2lvbjApIDwtIGFycmF5X2dlbmVfbmFtZXMKCiNOb3csIEkgd2FudCB0byBjaGFuZ2UgdGhlIHZhbHVlcyBvZiBjb2x1bW4gMSBvZiB0aGUgQUhCQV9wYXJjZWxfZXhwcmVzc2lvbjAgZGF0YWZyYW1lIHRvIHRoZSB2YWx1ZXMgaW4gdGhlIHJlZ2lvbl9hcnJheSBkYXRhZnJhbWUKI01heWJlIEkganVzdCBtdXRhdGUgdGhlIGRhdGFmcmFtZSB0byBhZGQgdGhlIGFycmF5IGFzIGEgY29sdW1uLCBtb3ZlIHRoYXQgY29sdW1uIHRvIHRoZSBmcm9udCwgYW5kIHRoZW4gcmVtb3ZlIHRoZSBvcmlnaW5hbCBjb2x1bW4KQUhCQV9wYXJjZWxfZXhwcmVzc2lvbjBfbGFiZWxlZCA8LSBBSEJBX3BhcmNlbF9leHByZXNzaW9uMCAlPiUKICBtdXRhdGUocmVnaW9uID0gcmVnaW9uX2FycmF5KSAlPiUKICAjTm93IGkgd2FudCB0byBtb3ZlIHRoZSByZWdpb24keDEgdmFyIHRvIGJlIHRoZSBmaXJzdCBjb2x1bW4KICBzZWxlY3QocmVnaW9uLCBldmVyeXRoaW5nKCkpICU+JQogIHNlbGVjdCgtIjAiKQoKI1lheSBub3cgZGF0YSB0YWJsZSBpcyBhcyBpIHdhbnQgaXQgdG8gYmUhCiMgTm93IEkgd2lsbCBwaXZvdCB0aGUgdGFibGUgc28gdGhhdCBpdCBtYXRjaGVzIHRoZSBBSEJBX3NpZ19nZW5lc19hbGxfcGl2b3QgdGFibGUKQUhCQV9ub3JtZWRfcGl2b3QgPC0gQUhCQV9wYXJjZWxfZXhwcmVzc2lvbjBfbGFiZWxlZCAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1yZWdpb24sIG5hbWVzX3RvID0gImdlbmVfc3ltYm9sIiwgdmFsdWVzX3RvID0gImV4cHJlc3Npb24iKSAlPiUKICBtdXRhdGUoaW5fMTZwX3JlZ2lvbiA9IGlmZWxzZShnZW5lX3N5bWJvbCAlaW4lIHNpeHRlZW5fcF8xMS4yX2dlbmVzLCAiWWVzIiwgIk5vIikpICU+JQogIHVubmVzdChjb2xzID0gcmVnaW9uKQoKCgpBSEJBX25vcm1lZF9waXZvdF9zaWdPTkxZIDwtIEFIQkFfbm9ybWVkX3Bpdm90ICU+JQogIGZpbHRlcihnZW5lX3N5bWJvbCAlaW4lIHNpZ19nZW5lX2xpc3QpCgoKIyBOb3csIEkgd2FudCB0byBjaGFuZ2UgdGhlIGNvbHVtbiBuYW1lIFgxIHRvIHJlZ2lvbgpjb2xuYW1lcyhBSEJBX25vcm1lZF9waXZvdF9zaWdPTkxZKVsxXSA8LSAicmVnaW9uIgoKYGBgCgpFeHBvcnRpbmcgZGF0YWZyYW1lcyBhcyBDU1ZzCmBgYHtyfQojIE9LLCBOb3cgdGhhdCBJIGhhdmUgdGhpcyBkYXRhLCBJIHdhbnQgdG8gcHV0IGl0IGludG8gYSBDU1Ygc28gSSBoYXZlIGl0IGZvciBmdXR1cmUgcmVmZXJlbmNlCnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9hYXJvbl9sYWJfMjAyNC9vdXRwdXQiKQp3cml0ZS5jc3YoQUhCQV9ub3JtZWRfcGl2b3QsICJOb3JtZWRfQUhCQV9zaWdfZ2VuZXMuY3N2IikKd3JpdGUuY3N2KEFIQkFfbm9ybWVkX3Bpdm90X3NpZ09OTFksICJOb3JtZWRfQUhCQV9zaWdfZ2VuZXNfT05MWS5jc3YiKQp3cml0ZS5jc3YoQUhCQV9zaWdfZ2VuZXNfcGl2b3QsICJSYXdfQUhCQV9zaWdfZ2VuZXNfT05MWS5jc3YiKQpgYGAKCgpQbG90dGluZyB0aGUgbm9ybWFsaXplZCBBSEJBIGRhdGEKYGBge3J9CmdncGxvdChBSEJBX25vcm1lZF9waXZvdF9zaWdPTkxZLCBhZXMoeD1leHByZXNzaW9uLCB5PXJlZ2lvbiwgY29sb3I9Z2VuZV9zeW1ib2wpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGxhYnModGl0bGUgPSAiTk9STUFMSVpFRCByZWdpb25hbCBleHByZXNzaW9uIG9mIHNpZ25pZmljYW50IGdlbmVzIGZyb20gMTZwIGRlbCBtZXRhLWFuYWx5c2lzIiwgeCA9ICJOb3JtYWxpemVkIEV4cHJlc3Npb24iLCB5ID0gIkJyYWluIFJlZ2lvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogICNJIHdpbGwgcmVtb3ZlIHRoZSBsZWdlbmQgYmVjYXVzZSBpdCBpcyB0b28gYmlnCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCiMgVmlzdWFsaXppbmcgZXhwcmVzc2lvbiBkYXRhIG9mIHNpZ25pZmljYW50IGdlbmVzCmdncGxvdChBSEJBX25vcm1lZF9waXZvdF9zaWdPTkxZLCBhZXMoeD1leHByZXNzaW9uLCB5PXJlZ2lvbiwgc2hhcGU9aW5fMTZwX3JlZ2lvbiwgY29sb3I9Z2VuZV9zeW1ib2wpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGxhYnModGl0bGUgPSAiTk9STUFMSVpFRCByZWdpb25hbCBleHByZXNzaW9uIG9mIHNpZ25pZmljYW50IGdlbmVzIGZyb20gMTZwIGRlbCBtZXRhLWFuYWx5c2lzIiwgeCA9ICJOb3JtYWxpemVkIEV4cHJlc3Npb24iLCB5ID0gIkJyYWluIFJlZ2lvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogICNJIHdpbGwgbWFrZSB0aGUgbGVnZW5kIHNtYWxsZXIgYW5kIHB1dCBpdCB1bmRlcm5lYXRoIHRoZSBncmFwaCAgYmVjYXVzZSBpdCBpcyB0b28gYmlnCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3I9Im5vbmUiKQoKIyBzYW1lIHBsb3QgYnV0IGFlc3RoZXRpY3Mgb25seSBmb3IgZ2VuZXMgaW4gMTZwIHJlZ2lvbgpnZ3Bsb3QoQUhCQV9ub3JtZWRfcGl2b3Rfc2lnT05MWSwgYWVzKHg9ZXhwcmVzc2lvbiwgeT1yZWdpb24sIGNvbG9yPWluXzE2cF9yZWdpb24pKSArIAogIGdlb21fcG9pbnQoKSArIAogIGxhYnModGl0bGUgPSAiTk9STUFMSVpFRCByZWdpb25hbCBleHByZXNzaW9uIG9mIHNpZ25pZmljYW50IGdlbmVzIGZyb20gMTZwIGRlbCBtZXRhLWFuYWx5c2lzIiwgeCA9ICJOb3JtYWxpemVkIEV4cHJlc3Npb24iLCB5ID0gIkJyYWluIFJlZ2lvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogICNJIHdpbGwgbWFrZSB0aGUgbGVnZW5kIHNtYWxsZXIgYW5kIHB1dCBpdCB1bmRlcm5lYXRoIHRoZSBncmFwaCAgYmVjYXVzZSBpdCBpcyB0b28gYmlnCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpIApgYGAKCk5vdyBJIHdpbGwgbWFwIHRoZSBub3JtYWxpemVkIEFIQkEgZGF0YSB0byBTbXJpdGhpJ3MgTVJJIGRhdGEsIHdoaWNoIGlzIGluIGEgY3N2IGZpbGU6IDE2cGFuYWx5c2lzX0JIX2FkanVzdGVkLmNzdgoKSW1wb3J0aW5nIG5lY2Vzc2FyeSBmaWxlcwpgYGB7cn0KIyBJbXBvcnRpbmcgU21yaXRoaSdzIE1SSSBkYXRhc2V0CnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9hYXJvbl9sYWJfMjAyNC9vdXRwdXQiKQpNUkkgPC0gcmVhZF9jc3YoIjE2cGFuYWx5c2lzX0JIX2FkanVzdGVkLmNzdiIpCgojIE91dHNpZGUgb2YgUiwgSSBoYXZlIG1hZGUgYSBDU1Ygb2YgY29ycmVzcG9uZGluZyBBSEJBIGFuZCBTbXJpdGhpIE1SSSBkYXRhIHJlZ2lvbiBuYW1lcy4gRmlyc3QgY29sdW1uIGlzIEFIQkEgbmFtZXMsIHNlY29uZCBjb2x1bW4gaXMgTVJJIG5hbWVzLgojIEltcG9ydGluZyB0aGUgZGF0YQpzZXR3ZCgiL1VzZXJzL3RhbW15cmF5L0Rlc2t0b3AvYWFyb25fbGFiXzIwMjQvQ1NWX2RhdGFfc2hlZXRzIikKc3RhbmRhcmRfcmVnaW9uX25hbWVzIDwtIHJlYWRfY3N2KCJBSEJBX01SSV9yZWdpb25fbmFtZXMuY3N2IikKCiMgUmVtZW1iZXJpbmcgb3RoZXIgZmlsZXMgSSB3aWxsIHVzZSBpbiB0aGUgZm9sbG93aW5nIGNodW5rcwpzaXh0ZWVuX3BfMTEuMl9nZW5lcyAjdmVjdG9yIG9mIGFsbCBnZW5lcyBpbiAxNnAgbG9jdXMKYGBgCgoKVGlkeWluZyBTbXJpdGhpJ3MgTVJJIGRhdGEKYGBge3J9CiMgV2UgZGVjaWRlZCB0aGF0IHdlIG9ubHkgd2FudCB0byB1c2UgbW9kZWwgMywgU3BsaW5lIFRDViBtb2RlbCAoZGVjaWRlZCB3IFNtcml0aGkgbWVldGluZyA4LzI0LzI0KQojIFdlIGFyZSBvbmx5IHVzaW5nIHRoZSBkZWxldGlvbiBkYXRhIGZvciBub3cKTVJJX21vZGVsMyA8LSBNUkkgJT4lCiAgZmlsdGVyKEdlbm90eXBlID09ICJHZW5vdHlwZTE2cERlbGV0aW9uLi4uNSIpCgojTVJJIHJlZ2lvbnMgdG8gcmVtb3ZlLiBJIG1hZGUgdGhpcyBsaXN0IG1hbnVhbGx5IHVzaW5nIGdvb2dsZSBzaGVldHMgYW5kIHJlZm9ybWF0dGVkIGl0IGZvciBSIHVzaW5nIGNoYXRncHQKTVJJX3JlZ2lvbnNfdG9fcmVtb3ZlIDwtIGMoIkwuQ2VyZWJyYWxfV00iLCAiTC5jZXJlYnJhbF9jb3J0ZXgiLCAiTC5sYXRlcmFsX3ZlbnRyaWNsZSIsICJMLmluZmVyaW9yX2xhdGVyYWxfdmVudHJpY2xlIiwgIkwuY2VyZWJlbGx1bV9XTSIsICJMLmNlcmViZWxsdW1fY29ydGV4IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJMLnRoYWxhbXVzIiwgIkwuY2F1ZGF0ZSIsICJMLnB1dGFtZW4iLCAiTC5wYWxsaWR1bSIsICJMLmFjY3VtYmVucyIsICJMLmhpcHBvY2FtcHVzIiwgIkwuYW15Z2RhbGEiLCAiTC52ZW50cmFsX0RDIiwgIlRoaXJkX1ZlbnRyaWNsZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiRm91cnRoX1ZlbnRyaWNsZSIsICJCcmFpbnN0ZW0iLCAiQ1NGIiwgIlIuQ2VyZWJyYWxfV00iLCAiUi5jZXJlYnJhbF9jb3J0ZXgiLCAiUi5sYXRlcmFsX3ZlbnRyaWNsZSIsICJSLmluZmVyaW9yX2xhdGVyYWxfdmVudHJpY2xlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJSLmNlcmViZWxsdW1fV00iLCAiUi5jZXJlYmVsbHVtX2NvcnRleCIsICJSLnRoYWxhbXVzIiwgIlIuY2F1ZGF0ZSIsICJSLnB1dGFtZW4iLCAiUi5wYWxsaWR1bSIsICJSLmhpcHBvY2FtcHVzIiwgIlIuYW15Z2RhbGEiLCAiUi5hY2N1bWJlbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlIudmVudHJhbF9EQyIsICJSLmN0eF9iYW5rc3N0cyIsICJSLmN0eF9jYXVkYWxhbnRlcmlvcmNpbmd1bGF0ZSIsICJSLmN0eF9jYXVkYWxtaWRkbGVmcm9udGFsIiwgIlIuY3R4X2N1bmV1cyIsICJSLmN0eF9lbnRvcmhpbmFsIiwgIlIuY3R4X2Z1c2lmb3JtIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJSLmN0eF9pbmZlcmlvcnBhcmlldGFsIiwgIlIuY3R4X2luZmVyaW9ydGVtcG9yYWwiLCAiUi5jdHhfaXN0aG11c2Npbmd1bGF0ZSIsICJSLmN0eF9sYXRlcmFsb2NjaXBpdGFsIiwgIlIuY3R4X2xhdGVyYWxvcmJpdG9mcm9udGFsIiwgIlIuY3R4X2xpbmd1YWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlIuY3R4X21lZGlhbG9yYml0b2Zyb250YWwiLCAiUi5jdHhfbWlkZGxldGVtcG9yYWwiLCAiUi5jdHhfcGFyYWhpcHBvY2FtcGFsIiwgIlIuY3R4X3BhcmFjZW50cmFsIiwgIlIuY3R4X3BhcnNvcGVyY3VsYXJpcyIsICJSLmN0eF9wYXJzb3JiaXRhbGlzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJSLmN0eF9wYXJzdHJpYW5ndWxhcmlzIiwgIlIuY3R4X3BlcmljYWxjYXJpbmUiLCAiUi5jdHhfcG9zdGNlbnRyYWwiLCAiUi5jdHhfcG9zdGVyaW9yY2luZ3VsYXRlIiwgIlIuY3R4X3ByZWNlbnRyYWwiLCAiUi5jdHhfcHJlY3VuZXVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJSLmN0eF9yb3N0cmFsYW50ZXJpb3JjaW5ndWxhdGUiLCAiUi5jdHhfcm9zdHJhbG1pZGRsZWZyb250YWwiLCAiUi5jdHhfc3VwZXJpb3Jmcm9udGFsIiwgIlIuY3R4X3N1cGVyaW9ycGFyaWV0YWwiLCAiUi5jdHhfc3VwZXJpb3J0ZW1wb3JhbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiUi5jdHhfc3VwcmFtYXJnaW5hbCIsICJSLmN0eF9mcm9udGFscG9sZSIsICJSLmN0eF90ZW1wb3JhbHBvbGUiLCAiUi5jdHhfdHJhbnN2ZXJzZXRlbXBvcmFsIiwgIlIuY3R4X2luc3VsYSIsICJjR01WIiwgIldNViIsICJzR01WIiwgIlZlbnRyaWNsZXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNlcmViZWxsdW0iLCAiQWNjdW1iZW5zIiwgIlZlbnRyYWxfRGllbmNlcGhhbG9uIiwgIlBhbGxpZHVtIiwgIkhpcHBvY2FtcHVzIiwgIkNhdWRhdGUiLCAiQ2VyZWJyYWxfV2hpdGVfTWF0dGVyIiwgIkxhdGVyYWxfVmVudHJpY2xlIiwgIkNlcmVicmFsX0NvcnRleCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiVGhhbGFtdXMiLCAiUHV0YW1lbiIsICJBbXlnZGFsYSIsICJDZXJlYmVsbGFyX1doaXRlX01hdHRlciIsICJDZXJlYmVsbGFyX0NvcnRleCIsICJJbmZlcmlvcl9MYXRlcmFsX1ZlbnRyaWNsZSIsICJjdHhfYmFua3NzdHMiLCAiY3R4X2NhdWRhbGFudGVyaW9yY2luZ3VsYXRlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdHhfY2F1ZGFsbWlkZGxlZnJvbnRhbCIsICJjdHhfY3VuZXVzIiwgImN0eF9lbnRvcmhpbmFsIiwgImN0eF9mdXNpZm9ybSIsICJjdHhfaW5mZXJpb3JwYXJpZXRhbCIsICJjdHhfaW5mZXJpb3J0ZW1wb3JhbCIsICJjdHhfaXN0aG11c2Npbmd1bGF0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiY3R4X2xhdGVyYWxvY2NpcGl0YWwiLCAiY3R4X2xhdGVyYWxvcmJpdG9mcm9udGFsIiwgImN0eF9saW5ndWFsIiwgImN0eF9tZWRpYWxvcmJpdG9mcm9udGFsIiwgImN0eF9taWRkbGV0ZW1wb3JhbCIsICJjdHhfcGFyYWhpcHBvY2FtcGFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdHhfcGFyYWNlbnRyYWwiLCAiY3R4X3BhcnNvcGVyY3VsYXJpcyIsICJjdHhfcGFyc29yYml0YWxpcyIsICJjdHhfcGFyc3RyaWFuZ3VsYXJpcyIsICJjdHhfcGVyaWNhbGNhcmluZSIsICJjdHhfcG9zdGNlbnRyYWwiLCAiY3R4X3Bvc3RlcmlvcmNpbmd1bGF0ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAiY3R4X3ByZWNlbnRyYWwiLCAiY3R4X3ByZWN1bmV1cyIsICJjdHhfcm9zdHJhbGFudGVyaW9yY2luZ3VsYXRlIiwgImN0eF9yb3N0cmFsbWlkZGxlZnJvbnRhbCIsICJjdHhfc3VwZXJpb3Jmcm9udGFsIiwgImN0eF9zdXBlcmlvcnBhcmlldGFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJjdHhfc3VwZXJpb3J0ZW1wb3JhbCIsICJjdHhfc3VwcmFtYXJnaW5hbCIsICJjdHhfZnJvbnRhbHBvbGUiLCAiY3R4X3RlbXBvcmFscG9sZSIsICJjdHhfdHJhbnN2ZXJzZXRlbXBvcmFsIiwgImN0eF9pbnN1bGEiKQoKIyByZW1vdmluZyByb3dzIGZvciB0aGUgcmVnaW9ucyB3ZSBhcmVuJ3QgaW5jbHVkaW5nCk1SSV9tb2RlbDNfbGVmdEhlbSA8LSBNUklfbW9kZWwzICU+JQogIGZpbHRlcihWb2x1bWV0cmljQ29tcG9uZW50ICVpbiUgTVJJX3JlZ2lvbnNfdG9fcmVtb3ZlID09IEZBTFNFKSAlPiUKICByZW5hbWUocmVnaW9uID0gVm9sdW1ldHJpY0NvbXBvbmVudCkKCiMgTm93LCBJIHdhbnQgdG8gdXNlIHRoZSBzdGFuZGFyZCByZWdpb24Kc3RhbmRhcmRfcmVnaW9uX25hbWVzIDwtIHN0YW5kYXJkX3JlZ2lvbl9uYW1lcyAlPiUKICByZW5hbWUocmVnaW9uID0gImxlZnQgaGVtaXNwaGVyZSBTbXJpdGhpIHJlZ2lvbnMiLAogICAgICAgICBuZXdfcmVnaW9uID0gIkFIQkEgcmVnaW9ucyIpCgojIFVzZSBsZWZ0X2pvaW4gdG8gbWFwIHRoZSBuZXcgbmFtZXMgYmFzZWQgb24gdGhlIHJlZ2lvbiB2YXJpYWJsZQpNUklfbW9kZWwzX2xlZnRIZW1fbmV3X3JlZ2lvbk5hbWVzIDwtIE1SSV9tb2RlbDNfbGVmdEhlbSAlPiUKICBsZWZ0X2pvaW4oc3RhbmRhcmRfcmVnaW9uX25hbWVzLCBieSA9ICJyZWdpb24iKSAlPiUgICAjIEpvaW4gYmFzZWQgb24gdGhlIHJlZ2lvbiB2YXJpYWJsZQogIG11dGF0ZShyZWdpb24gPSBpZmVsc2UoIWlzLm5hKG5ld19yZWdpb24pLCBuZXdfcmVnaW9uLCByZWdpb24pKSAlPiUgICAjIFJlcGxhY2UgcmVnaW9uIG5hbWVzIHdpdGggbmV3IG9uZXMKICBzZWxlY3QoLW5ld19yZWdpb24pICAjIFJlbW92ZSB0aGUgZXh0cmEgY29sdW1uIGlmIG5lZWRlZAoKYGBgCgoKTWVyZ2luZyB0aGUgQUhCQSBub3JtZWQgdmFsdWVzIHdpdGggU21yaXRoaSdzIE1SSSBkYXRhCmBgYHtyfQpBSEJBX01SSV9tZXJnZWQgPC0gZnVsbF9qb2luKEFIQkFfbm9ybWVkX3Bpdm90X3NpZ09OTFksIE1SSV9tb2RlbDNfbGVmdEhlbV9uZXdfcmVnaW9uTmFtZXMsIGJ5ID0gInJlZ2lvbiIsIG11bHRpcGxlID0gImFsbCIpCgpBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkIDwtIEFIQkFfTVJJX21lcmdlZCAlPiUKICBzZWxlY3QoLUdlbm90eXBlKQoKY29sbmFtZXMoQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZClbM10gPC0gIkFIQkFfZXhwcmVzc2lvbiIKY29sbmFtZXMoQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZClbOF0gPC0gInRfdmFsdWUiCgpgYGAKCgpFeHBvcnRpbmcgYXMgY3N2IEFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWQKYGBge3J9CnNldHdkKCIvVXNlcnMvdGFtbXlyYXkvRGVza3RvcC9hYXJvbl9sYWJfMjAyNC9DU1ZfZGF0YV9zaGVldHMiKQp3cml0ZV9jc3YoQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZCwgIkFIQkFfTVJJX21lcmdlZC5jc3YiKQpgYGAKClBlYXJzb24gY29ycmVsYXRpb24gYW5hbHlzaXMKSSB3YW50IHRvIGRvIGEgY29ycmVsYXRpb24gYW5hbHlzaXMgYmV0d2VlbiB0aGUgQUhCQSBleHByZXNzaW9uIGFuZCB0aGUgTVJJIGRhdGEKCkNyZWF0aW5nIGZ1bmN0aW9ucyB0byBjb21wdXRlIGNvcnJlbGF0aW9uIGFuZCBwLXZhbHVlLCBjcmVhdGVkIGJ5IENoYXRHUFQKYGBge3J9CmNvcnJlbGF0aW9uX3dpdGhfcHZhbHVlX3BlYXJzb24gPC0gZnVuY3Rpb24oeCwgeSkgewogIHRlc3QgPC0gY29yLnRlc3QoeCwgeSwgbWV0aG9kID0gInBlYXJzb24iKQogIHJldHVybihkYXRhLmZyYW1lKGNvcnJlbGF0aW9uID0gdGVzdCRlc3RpbWF0ZSwgcF92YWx1ZSA9IHRlc3QkcC52YWx1ZSkpCn0KCmNvcnJlbGF0aW9uX3dpdGhfcHZhbHVlX3NwZWFybWFuIDwtIGZ1bmN0aW9uKHgsIHkpIHsKICB0ZXN0IDwtIGNvci50ZXN0KHgsIHksIG1ldGhvZCA9ICJzcGVhcm1hbiIpCiAgcmV0dXJuKGRhdGEuZnJhbWUoY29ycmVsYXRpb24gPSB0ZXN0JGVzdGltYXRlLCBwX3ZhbHVlID0gdGVzdCRwLnZhbHVlKSkKfQpgYGAKClJ1bm5pbmcgdGhlIGNvcnJlbGF0aW9uIGFuYWx5c2lzCmBgYHtyfQojIEdyb3VwIGJ5IGdlbmVfc3ltYm9sIGFuZCBjb21wdXRlIGNvcnJlbGF0aW9uIGJldHdlZW4gQUhCQV9leHByZXNzaW9uIGFuZCBFc3RpbWF0ZQpjb3JfcmVzdWx0c19Fc3RpbWF0ZV9wZWFyc29uIDwtIEFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWQgJT4lCiAgZ3JvdXBfYnkoZ2VuZV9zeW1ib2wpICU+JQogIHN1bW1hcml6ZShjb3JyZWxhdGlvbiA9IGNvcihBSEJBX2V4cHJlc3Npb24sIEVzdGltYXRlLCBtZXRob2QgPSAicGVhcnNvbiIpLAogICAgICAgICAgICBwX3ZhbHVlID0gY29ycmVsYXRpb25fd2l0aF9wdmFsdWVfcGVhcnNvbihBSEJBX2V4cHJlc3Npb24sIEVzdGltYXRlKSRwX3ZhbHVlKSAlPiUKICBtdXRhdGUoaW5fMTZwX2xvY3VzID0gaWZlbHNlKGdlbmVfc3ltYm9sICVpbiUgc2l4dGVlbl9wXzExLjJfZ2VuZXMsICJZZXMiLCAiTm8iKSkKCiNUcnlpbmcgYSBzcGVhcm1hbiBjb3JyZWxhdGlvbiBhbmFseXNpcyBpbnN0ZWFkCmNvcl9yZXN1bHRzX0VzdGltYXRlX3NwZWFybWFuIDwtIEFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWQgJT4lCiAgZ3JvdXBfYnkoZ2VuZV9zeW1ib2wpICU+JQogIHN1bW1hcml6ZShjb3JyZWxhdGlvbiA9IGNvcihBSEJBX2V4cHJlc3Npb24sIEVzdGltYXRlLCBtZXRob2QgPSAic3BlYXJtYW4iKSwKICAgICAgICAgICAgcF92YWx1ZSA9IGNvci50ZXN0KEFIQkFfZXhwcmVzc2lvbiwgRXN0aW1hdGUsIG1ldGhvZCA9ICJzcGVhcm1hbiIpJHAudmFsdWUpICU+JQogIG11dGF0ZShpbl8xNnBfbG9jdXMgPSBpZmVsc2UoZ2VuZV9zeW1ib2wgJWluJSBzaXh0ZWVuX3BfMTEuMl9nZW5lcywgIlllcyIsICJObyIpKQoKIyBEb2luZyB0aGUgc2FtZSB0aGluZyBmb3IgdGhlIHQgdmFsdWUKIyBQZWFyc29uIGNvcnJlbGF0aW9uCmNvcl9yZXN1bHRzX3RfdmFsdWVfcGVhcnNvbiA8LSBBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkICU+JQogIGdyb3VwX2J5KGdlbmVfc3ltYm9sKSAlPiUKICBzdW1tYXJpemUoY29ycmVsYXRpb24gPSBjb3IoQUhCQV9leHByZXNzaW9uLCB0X3ZhbHVlLCBtZXRob2QgPSAicGVhcnNvbiIpLAogICAgICAgICAgICBwX3ZhbHVlID0gY29ycmVsYXRpb25fd2l0aF9wdmFsdWVfcGVhcnNvbihBSEJBX2V4cHJlc3Npb24sIHRfdmFsdWUpJHBfdmFsdWUpICU+JQogIG11dGF0ZShpbl8xNnBfbG9jdXMgPSBpZmVsc2UoZ2VuZV9zeW1ib2wgJWluJSBzaXh0ZWVuX3BfMTEuMl9nZW5lcywgIlllcyIsICJObyIpKQoKI1NwZWFybWFuIGNvcnJlbGF0aW9uCmNvcl9yZXN1bHRzX3RfdmFsdWVfc3BlYXJtYW4gPC0gQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZCAlPiUKICBncm91cF9ieShnZW5lX3N5bWJvbCkgJT4lCiAgc3VtbWFyaXplKGNvcnJlbGF0aW9uID0gY29yKEFIQkFfZXhwcmVzc2lvbiwgdF92YWx1ZSwgbWV0aG9kID0gInNwZWFybWFuIiksCiAgICAgICAgICAgIHBfdmFsdWUgPSBjb3IudGVzdChBSEJBX2V4cHJlc3Npb24sIHRfdmFsdWUsIG1ldGhvZCA9ICJzcGVhcm1hbiIpJHAudmFsdWUpICU+JQogIG11dGF0ZShpbl8xNnBfbG9jdXMgPSBpZmVsc2UoZ2VuZV9zeW1ib2wgJWluJSBzaXh0ZWVuX3BfMTEuMl9nZW5lcywgIlllcyIsICJObyIpKQpgYGAKCgpFeHBvcnRpbmcgdGhlIGNvcnJlbGF0aW9uIGFuYWx5c2lzIGRhdGFmcmFtZXMgdG8gQ1NWIGZpbGVzCmBgYHtyfQpzZXR3ZCgiL1VzZXJzL3RhbW15cmF5L0Rlc2t0b3AvYWFyb25fbGFiXzIwMjQvQ1NWX2RhdGFfc2hlZXRzIikKd3JpdGVfY3N2KGNvcl9yZXN1bHRzX0VzdGltYXRlX3BlYXJzb24sICJBSEJBX01SSV9jb3JyZWxhdGlvbl9Fc3RpbWF0ZV9QZWFyc29uLmNzdiIpCndyaXRlX2Nzdihjb3JfcmVzdWx0c19Fc3RpbWF0ZV9zcGVhcm1hbiwgIkFIQkFfTVJJX2NvcnJlbGF0aW9uX0VzdGltYXRlX1NwZWFybWFuLmNzdiIpCndyaXRlX2Nzdihjb3JfcmVzdWx0c190X3ZhbHVlX3BlYXJzb24sICJBSEJBX01SSV9jb3JyZWxhdGlvbl90X3ZhbHVlX1BlYXJzb24uY3N2IikKd3JpdGVfY3N2KGNvcl9yZXN1bHRzX3RfdmFsdWVfc3BlYXJtYW4sICJBSEJBX01SSV9jb3JyZWxhdGlvbl90X3ZhbHVlX1NwZWFybWFuLmNzdiIpCmBgYAoKCk5vdywgSSB3YW50IHRvIHZpc3VhbGl6ZSB0aGUgY29ycmVsYXRpb24gZGF0YQpgYGB7cn0KI1NjYXR0ZXJwbG90IHNob3dpbmcgcmVsYXRpb25zaGlwIGJldHdlZW4gcCB2YWx1ZSBhbmQgY29ycmVsYXRpb24sIG5vdCBzdXBlciB1c2VmdWwgYnV0IGVkdWNhdGlvbmFsIGZvciBtZSEKZ2dwbG90KGNvcl9yZXN1bHRzX3RfdmFsdWVfc3BlYXJtYW4sIGFlcyh4PXBfdmFsdWUsIHk9Y29ycmVsYXRpb24sIGNvbG9yPWluXzE2cF9sb2N1cykpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnModGl0bGUgPSAiU3BlYXJtYW4gY29ycmVsYXRpb24gb2YgdC12YWx1ZSIsCiAgICAgICB4ID0gInAgdmFsdWUiLAogICAgICAgeSA9ICJjb3JyZWxhdGlvbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gMC4wNSkpCgojbWFraW5nIGEgZGVuc2l0eSBjdXJ2ZSBpbnN0ZWFkPwpnZ3Bsb3QoY29yX3Jlc3VsdHNfdF92YWx1ZV9zcGVhcm1hbiwgYWVzKHg9Y29ycmVsYXRpb24sIGNvbG9yPWluXzE2cF9sb2N1cykpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgbGFicyh0aXRsZSA9ICJTcGVhcm1hbiBjb3JyZWxhdGlvbiBvZiB0LXZhbHVlIiwKICAgICAgIHggPSAiQ29ycmVsYXRpb24gQ29lZmZpY2llbnQiLAogICAgICAgeSA9ICJEZW5zaXR5IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBtYWtpbmcgYSBoaXN0b2dyYW0gaW5zdGVhZApnZ3Bsb3QoY29yX3Jlc3VsdHNfdF92YWx1ZV9zcGVhcm1hbiwgYWVzKHg9IGFicyhjb3JyZWxhdGlvbiksIGZpbGw9aW5fMTZwX2xvY3VzKSkgKwogIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYWxwaGEgPSAwLjYpICsKICBsYWJzKHRpdGxlID0gIlNwZWFybWFuIGNvcnJlbGF0aW9uIG9mIHQtdmFsdWUiLAogICAgICAgeCA9ICJBYnNvbHV0ZSBWYWx1ZSBvZiBDb3JyZWxhdGlvbiBDb2VmZmljaWVudCIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHhsaW0oMCwgMC42KSArIHlsaW0oMCwgOCkKCmdncGxvdChjb3JfcmVzdWx0c19Fc3RpbWF0ZV9zcGVhcm1hbiwgYWVzKHg9YWJzKGNvcnJlbGF0aW9uKSwgZmlsbD1pbl8xNnBfbG9jdXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuNikgKwogIGxhYnModGl0bGUgPSAiU3BlYXJtYW4gY29ycmVsYXRpb24gb2YgRXN0aW1hdGUofmVmZmVjdCBzaXplKSIsCiAgICAgICB4ID0gIkFic29sdXRlIFZhbHVlIG9mIENvcnJlbGF0aW9uIENvZWZmaWNpZW50IiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgeGxpbSgwLCAwLjYpICsgeWxpbSgwLCA4KQpgYGAKCk5vdyBJIHdhbnQgdG8gcGxvdCB0aGUgZGF0YQpgYGB7cn0KbGlicmFyeSgiZ2dwdWJyIikKbGlicmFyeShwbG90bHkpCmBgYAoKYGBge3J9CiNNYWtpbmcgYSBodWdlIHBsb3Qgd2l0aCBhIGxvdCBvZiBsaXR0bGUgcGxvdHMgaW5zaWRlIChjb3VydGVzeSBvZiBmYWNldF93cmFwKSBvZiBhbGwgZ2VuZXMKc2NhdHRlcl9wbG90X2VzdGltYXRlIDwtIGdncGxvdChBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkLCBhZXMoeCA9IEFIQkFfZXhwcmVzc2lvbiwgeSA9IEVzdGltYXRlLCBjb2xvciA9IHJlZ2lvbikpICsKICBnZW9tX3BvaW50KHNpemUgPSAwLjEpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmx1ZSIsIGxpbmV3aWR0aCA9IDAuNSkgKyAgIyBBZGQgYSBsaW5lIG9mIGJlc3QgZml0IChsaW5lYXIgcmVncmVzc2lvbikKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXIgcGxvdHMgb2YgQUhCQSBFeHByZXNzaW9uIHZzIEVzdGltYXRlIGZvciBhbGwgR2VuZXMiLAogICAgICAgeCA9ICJBSEJBIEV4cHJlc3Npb24iLAogICAgICAgeSA9ICJFc3RpbWF0ZSIpICsKICBmYWNldF93cmFwKH4gZ2VuZV9zeW1ib2wsIHNjYWxlcyA9ICJmcmVlIikgKyAgIyBTZXBhcmF0ZSBwbG90cyBmb3IgZWFjaCBnZW5lCiAgdGhlbWVfbWluaW1hbCgpICsKICB4bGltKDAsIDEpICsgeWxpbSgtMC43LCAwLjcpICMrCiAgc3RhdF9jb3IoYWVzKGxhYmVsID0gcGFzdGUoLi5yLmxhYmVsLi4sIHNlcCA9ICJ+YCxgfiIpKSwgCiAgICAgICAgIG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDMsIGxhYmVsLnkgPSAwKSAgIyBBZGQgY29ycmVsYXRpb24gY29lZmZpY2llbnRzIHRvIHRoZSBwbG90CgojIENvbnZlcnQgdG8gYSBwbG90bHkgb2JqZWN0CmludGVyYWN0aXZlX3Bsb3RfZXN0aW1hdGUgPC0gZ2dwbG90bHkoc2NhdHRlcl9wbG90X2VzdGltYXRlLCB0b29sdGlwID0gYygidGV4dCIpKQppbnRlcmFjdGl2ZV9wbG90X2VzdGltYXRlICMgRGlzcGxheSB0aGUgaW50ZXJhY3RpdmUgcGxvdAoKI0RvaW5nIHRoZSBzYW1lIHBsb3QsIGJ1dCBmb3IgdC12YWx1ZQpzY2F0dGVyX3Bsb3RfdF92YWx1ZSA8LSBnZ3Bsb3QoQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZCwgYWVzKHggPSBBSEJBX2V4cHJlc3Npb24sIHkgPSBFc3RpbWF0ZSwgY29sb3IgPSByZWdpb24pKSArCiAgZ2VvbV9wb2ludChzaXplID0gMC4xKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImJsdWUiLCBsaW5ld2lkdGggPSAwLjUpICsgICMgQWRkIGEgbGluZSBvZiBiZXN0IGZpdCAobGluZWFyIHJlZ3Jlc3Npb24pCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVyIHBsb3RzIG9mIEFIQkEgRXhwcmVzc2lvbiB2cyBFc3RpbWF0ZSBmb3IgYWxsIEdlbmVzIiwKICAgICAgIHggPSAiQUhCQSBFeHByZXNzaW9uIiwKICAgICAgIHkgPSAiRXN0aW1hdGUiKSArCiAgZmFjZXRfd3JhcCh+IGdlbmVfc3ltYm9sLCBzY2FsZXMgPSAiZnJlZSIpICsgICMgU2VwYXJhdGUgcGxvdHMgZm9yIGVhY2ggZ2VuZQogIHRoZW1lX21pbmltYWwoKSArCiAgc3RhdF9jb3IoYWVzKGxhYmVsID0gcGFzdGUoLi5yLmxhYmVsLi4sIHNlcCA9ICJ+YCxgfiIpKSwgCiAgICAgICAgICAgbWV0aG9kID0gInBlYXJzb24iLCBsYWJlbC54ID0gMywgbGFiZWwueSA9IDApICAjIEFkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgdG8gdGhlIHBsb3QKCiMgQ29udmVydCB0byBhIHBsb3RseSBvYmplY3QKaW50ZXJhY3RpdmVfcGxvdF90X3ZhbHVlIDwtIGdncGxvdGx5KHNjYXR0ZXJfcGxvdF90X3ZhbHVlLCB0b29sdGlwID0gYygidGV4dCIpKQppbnRlcmFjdGl2ZV9wbG90X3RfdmFsdWUgIyBEaXNwbGF5IHRoZSBpbnRlcmFjdGl2ZSBwbG90CmBgYAoKCkRvaW5nIHRoZSBhYm92ZSBwbG90dGluZyBmb3IgdGhlIDE2cCBnZW5lcyBvbmx5CmBgYHtyfQojIERvaW5nIHRoZSBhYm92ZSBwbG90dGluZyBmb3IgdGhlIE5PTiAxNnAgZ2VuZXMgLS0tLQpBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkX05PVF9JTl8xNnBfbG9jdXMgPC0gQUhCQV9NUklfbWVyZ2VkX29yZ2FuaXplZCAlPiUgZmlsdGVyKGluXzE2cF9yZWdpb24gPT0gIk5vIikKCnNjYXR0ZXJfcGxvdF9OT1RfMTZwX2dlbmVzIDwtIGdncGxvdChBSEJBX01SSV9tZXJnZWRfb3JnYW5pemVkX05PVF9JTl8xNnBfbG9jdXMsIGFlcyh4ID0gQUhCQV9leHByZXNzaW9uLCB5ID0gRXN0aW1hdGUsIGNvbG9yID0gcmVnaW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJibHVlIiwgbGluZXdpZHRoID0gMC41LCBmdWxscmFuZ2UgPSBUUlVFKSArICAjIEFkZCBhIGxpbmUgb2YgYmVzdCBmaXQgKGxpbmVhciByZWdyZXNzaW9uKQogIGxhYnModGl0bGUgPSAiU2NhdHRlciBwbG90cyBvZiBBSEJBIEV4cHJlc3Npb24gdnMgRXN0aW1hdGUgZm9yIEdlbmVzIE5PVCBpbiAxNnAgbG9jdXMiLAogICAgICAgeCA9ICJBSEJBIEV4cHJlc3Npb24iLAogICAgICAgeSA9ICJFc3RpbWF0ZSIpICsKICBmYWNldF93cmFwKH4gZ2VuZV9zeW1ib2wsIHNjYWxlcyA9ICJmcmVlIikgKyAgIyBTZXBhcmF0ZSBwbG90cyBmb3IgZWFjaCBnZW5lCiAgdGhlbWVfbWluaW1hbCgpICsKICBzdGF0X2NvcihhZXMobGFiZWwgPSBwYXN0ZSguLnIubGFiZWwuLiwgc2VwID0gIn5gLGB+IikpLCAKICAgICAgICAgICBtZXRob2QgPSAicGVhcnNvbiIsIGxhYmVsLnggPSAzLCBsYWJlbC55ID0gMCkgKyAjIEFkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgdG8gdGhlIHBsb3QKICB4bGltKDAsIDEpICAjIEFkanVzdCBheGlzIGxpbWl0cwojIENvbnZlcnQgdG8gYSBwbG90bHkgb2JqZWN0CmludGVyYWN0aXZlX3Bsb3RfTk9UXzE2cF9nZW5lcyA8LSBnZ3Bsb3RseShzY2F0dGVyX3Bsb3RfTk9UXzE2cF9nZW5lcywgdG9vbHRpcCA9IGMoInRleHQiKSkKCiMgRGlzcGxheSB0aGUgaW50ZXJhY3RpdmUgcGxvdAppbnRlcmFjdGl2ZV9wbG90X05PVF8xNnBfZ2VuZXMKYGBgCgoKQWRkaW5nIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW5jaWVzIGFuZCBwIHZhbHVlcyB0byBwbG90cwoxLiBNYWtpbmcgbmV3IGRhdGFmcmFtdyB3aXRoIGZhY2V0IGxhYmVscwpgYGB7cn0KIyBNZXJnZSBtYWluIGRhdGEgd2l0aCBjb3JyZWxhdGlvbiByZXN1bHRzCnBsb3RfZGF0YV90X3ZhbHVlX3NwZWFybWFuIDwtIEFIQkFfTVJJX21lcmdlZF9vcmdhbml6ZWQgJT4lCiAgbGVmdF9qb2luKGNvcl9yZXN1bHRzX3RfdmFsdWVfc3BlYXJtYW4sIGJ5ID0gImdlbmVfc3ltYm9sIikgJT4lICMgTWVyZ2UgYnkgZ2VuZV9zeW1ib2wKICBtdXRhdGUoZmFjZXRfbGFiZWwgPSBwYXN0ZTAoZ2VuZV9zeW1ib2wsICJcbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAifCBSOiAiLCByb3VuZChjb3JyZWxhdGlvbiwgMiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLCBwOiAiLCByb3VuZChwX3ZhbHVlLCAzKSkpCmBgYAoKCjIuIHJlcGxvdHRpbmcgZGF0YQpgYGB7cn0KZ2dwbG90KHBsb3RfZGF0YV90X3ZhbHVlX3NwZWFybWFuLCBhZXMoeCA9IEFIQkFfZXhwcmVzc2lvbiwgeSA9IHRfdmFsdWUsIGNvbG9yID0gcmVnaW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSkgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJibHVlIiwgbGluZXdpZHRoID0gMC41LCBmdWxscmFuZ2UgPSBUUlVFKSArICAjIEFkZCBhIGxpbmUgb2YgYmVzdCBmaXQgKGxpbmVhciByZWdyZXNzaW9uKQogIGxhYnModGl0bGUgPSAiU2NhdHRlciBwbG90cyBvZiBBSEJBIEV4cHJlc3Npb24gdnMgdC12YWx1ZSBmb3IgYWxsIEdlbmVzIiwKICAgICAgIHggPSAiQUhCQSBFeHByZXNzaW9uIiwKICAgICAgIHkgPSAidC12YWx1ZSIpICsKICBmYWNldF93cmFwKH4gZmFjZXRfbGFiZWwsIHNjYWxlcyA9ICJmcmVlIikgKyAgIyBVc2UgdGhlIGN1c3RvbSBmYWNldCBsYWJlbAogIHRoZW1lX21pbmltYWwoKSArCiAgeGxpbSgwLCAxKSAjKyB5bGltKC0wLjcsIDAuNykgICMgQWRqdXN0IGF4aXMgbGltaXRzCmBgYAoKCgoKCgoK